Synchronize with trunk r58606.
[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 IOHCIRequest
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 IMP_IUSBREQUEST
40 IMP_IOHCIREQUEST
41
42 // local functions
43 ULONG InternalGetTransferType();
44 UCHAR InternalGetPidDirection();
45 UCHAR STDMETHODCALLTYPE GetDeviceAddress();
46 NTSTATUS BuildSetupPacket();
47 NTSTATUS BuildSetupPacketFromURB();
48 NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
49 NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
50 NTSTATUS BuildIsochronousEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
51 NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize);
52 VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor);
53 NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor);
54 NTSTATUS CreateIsochronousTransferDescriptor(OUT POHCI_ISO_TD *OutDescriptor, ULONG FrameCount);
55 UCHAR GetEndpointAddress();
56 USHORT GetMaxPacketSize();
57 VOID CheckError(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
58 VOID DumpEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR *Descriptor);
59 NTSTATUS BuildTransferDescriptorChain(IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, OUT POHCI_GENERAL_TD * OutFirstDescriptor, OUT POHCI_GENERAL_TD * OutLastDescriptor, OUT PULONG OutTransferBufferOffset);
60 VOID InitDescriptor(IN POHCI_GENERAL_TD CurrentDescriptor, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode);
61
62
63 // constructor / destructor
64 CUSBRequest(IUnknown *OuterUnknown){}
65 virtual ~CUSBRequest(){}
66
67 protected:
68 LONG m_Ref;
69
70 //
71 // memory manager for allocating setup packet / queue head / transfer descriptors
72 //
73 PDMAMEMORYMANAGER m_DmaManager;
74
75 //
76 // caller provided irp packet containing URB request
77 //
78 PIRP m_Irp;
79
80 //
81 // transfer buffer length
82 //
83 ULONG m_TransferBufferLength;
84
85 //
86 // current transfer length
87 //
88 ULONG m_TransferBufferLengthCompleted;
89
90 //
91 // Total Transfer Length
92 //
93 ULONG m_TotalBytesTransferred;
94
95 //
96 // transfer buffer MDL
97 //
98 PMDL m_TransferBufferMDL;
99
100 //
101 // caller provided setup packet
102 //
103 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
104
105 //
106 // completion event for callers who initialized request with setup packet
107 //
108 PKEVENT m_CompletionEvent;
109
110 //
111 // device address for callers who initialized it with device address
112 //
113 UCHAR m_DeviceAddress;
114
115 //
116 // store endpoint descriptor
117 //
118 PUSB_ENDPOINT m_EndpointDescriptor;
119
120 //
121 // allocated setup packet from the DMA pool
122 //
123 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
124 PHYSICAL_ADDRESS m_DescriptorSetupPacket;
125
126 //
127 // stores the result of the operation
128 //
129 NTSTATUS m_NtStatusCode;
130 ULONG m_UrbStatusCode;
131
132 //
133 // device speed
134 //
135 USB_DEVICE_SPEED m_DeviceSpeed;
136
137 //
138 // store urb
139 //
140 PURB m_Urb;
141
142 //
143 // base buffer
144 //
145 PVOID m_Base;
146 };
147
148 //----------------------------------------------------------------------------------------
149 NTSTATUS
150 STDMETHODCALLTYPE
151 CUSBRequest::QueryInterface(
152 IN REFIID refiid,
153 OUT PVOID* Output)
154 {
155 return STATUS_UNSUCCESSFUL;
156 }
157
158 //----------------------------------------------------------------------------------------
159 NTSTATUS
160 STDMETHODCALLTYPE
161 CUSBRequest::InitializeWithSetupPacket(
162 IN PDMAMEMORYMANAGER DmaManager,
163 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
164 IN PUSBDEVICE Device,
165 IN OPTIONAL struct _USB_ENDPOINT* EndpointDescriptor,
166 IN OUT ULONG TransferBufferLength,
167 IN OUT PMDL TransferBuffer)
168 {
169 //
170 // sanity checks
171 //
172 PC_ASSERT(DmaManager);
173 PC_ASSERT(SetupPacket);
174
175 //
176 // initialize packet
177 //
178 m_DmaManager = DmaManager;
179 m_SetupPacket = SetupPacket;
180 m_TransferBufferLength = TransferBufferLength;
181 m_TransferBufferMDL = TransferBuffer;
182 m_DeviceAddress = Device->GetDeviceAddress();
183 m_EndpointDescriptor = EndpointDescriptor;
184 m_TotalBytesTransferred = 0;
185 m_DeviceSpeed = Device->GetSpeed();
186
187 //
188 // Set Length Completed to 0
189 //
190 m_TransferBufferLengthCompleted = 0;
191
192 //
193 // allocate completion event
194 //
195 m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBOHCI);
196 if (!m_CompletionEvent)
197 {
198 //
199 // failed to allocate completion event
200 //
201 return STATUS_INSUFFICIENT_RESOURCES;
202 }
203
204 //
205 // initialize completion event
206 //
207 KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
208
209 //
210 // done
211 //
212 return STATUS_SUCCESS;
213 }
214 //----------------------------------------------------------------------------------------
215 NTSTATUS
216 STDMETHODCALLTYPE
217 CUSBRequest::InitializeWithIrp(
218 IN PDMAMEMORYMANAGER DmaManager,
219 IN struct IUSBDevice* Device,
220 IN OUT PIRP Irp)
221 {
222 PIO_STACK_LOCATION IoStack;
223
224 //
225 // sanity checks
226 //
227 PC_ASSERT(DmaManager);
228 PC_ASSERT(Irp);
229
230 m_DmaManager = DmaManager;
231 m_TotalBytesTransferred = 0;
232
233 //
234 // get current irp stack location
235 //
236 IoStack = IoGetCurrentIrpStackLocation(Irp);
237
238 //
239 // sanity check
240 //
241 PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
242 PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
243 PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
244
245 //
246 // get urb
247 //
248 m_Urb = (PURB)IoStack->Parameters.Others.Argument1;
249
250 //
251 // store irp
252 //
253 m_Irp = Irp;
254
255 //
256 // store speed
257 //
258 m_DeviceSpeed = Device->GetSpeed();
259
260 //
261 // check function type
262 //
263 switch (m_Urb->UrbHeader.Function)
264 {
265 case URB_FUNCTION_ISOCH_TRANSFER:
266 {
267 //
268 // there must be at least one packet
269 //
270 ASSERT(m_Urb->UrbIsochronousTransfer.NumberOfPackets);
271
272 //
273 // is there data to be transferred
274 //
275 if (m_Urb->UrbIsochronousTransfer.TransferBufferLength)
276 {
277 //
278 // Check if there is a MDL
279 //
280 if (!m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
281 {
282 //
283 // sanity check
284 //
285 PC_ASSERT(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
286
287 //
288 // Create one using TransferBuffer
289 //
290 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
291 m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
292 m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
293 FALSE,
294 FALSE,
295 NULL);
296
297 if (!m_TransferBufferMDL)
298 {
299 //
300 // failed to allocate mdl
301 //
302 return STATUS_INSUFFICIENT_RESOURCES;
303 }
304
305 //
306 // build mdl for non paged pool
307 // FIXME: Does hub driver already do this when passing MDL?
308 //
309 MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
310 }
311 else
312 {
313 //
314 // use provided mdl
315 //
316 m_TransferBufferMDL = m_Urb->UrbIsochronousTransfer.TransferBufferMDL;
317 }
318 }
319
320 //
321 // save buffer length
322 //
323 m_TransferBufferLength = m_Urb->UrbIsochronousTransfer.TransferBufferLength;
324
325 //
326 // Set Length Completed to 0
327 //
328 m_TransferBufferLengthCompleted = 0;
329
330 //
331 // get endpoint descriptor
332 //
333 m_EndpointDescriptor = (PUSB_ENDPOINT)m_Urb->UrbIsochronousTransfer.PipeHandle;
334
335 //
336 // completed initialization
337 //
338 break;
339 }
340 //
341 // luckily those request have the same structure layout
342 //
343 case URB_FUNCTION_CLASS_INTERFACE:
344 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
345 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
346 {
347 //
348 // bulk interrupt transfer
349 //
350 if (m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
351 {
352 //
353 // Check if there is a MDL
354 //
355 if (!m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
356 {
357 //
358 // sanity check
359 //
360 PC_ASSERT(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
361
362 //
363 // Create one using TransferBuffer
364 //
365 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
366 m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
367 m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
368 FALSE,
369 FALSE,
370 NULL);
371
372 if (!m_TransferBufferMDL)
373 {
374 //
375 // failed to allocate mdl
376 //
377 return STATUS_INSUFFICIENT_RESOURCES;
378 }
379
380 //
381 // build mdl for non paged pool
382 // FIXME: Does hub driver already do this when passing MDL?
383 //
384 MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
385
386 //
387 // Keep that ehci created the MDL and needs to free it.
388 //
389 }
390 else
391 {
392 m_TransferBufferMDL = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
393 }
394
395 //
396 // save buffer length
397 //
398 m_TransferBufferLength = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
399
400 //
401 // Set Length Completed to 0
402 //
403 m_TransferBufferLengthCompleted = 0;
404
405 //
406 // get endpoint descriptor
407 //
408 m_EndpointDescriptor = (PUSB_ENDPOINT)m_Urb->UrbBulkOrInterruptTransfer.PipeHandle;
409
410 }
411 break;
412 }
413 default:
414 DPRINT1("URB Function: not supported %x\n", m_Urb->UrbHeader.Function);
415 PC_ASSERT(FALSE);
416 }
417
418 //
419 // done
420 //
421 return STATUS_SUCCESS;
422
423 }
424
425 //----------------------------------------------------------------------------------------
426 BOOLEAN
427 STDMETHODCALLTYPE
428 CUSBRequest::IsRequestComplete()
429 {
430 //
431 // FIXME: check if request was split
432 //
433
434 //
435 // Check if the transfer was completed, only valid for Bulk Transfers
436 //
437 if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
438 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
439 {
440 //
441 // Transfer not completed
442 //
443 return FALSE;
444 }
445 return TRUE;
446 }
447 //----------------------------------------------------------------------------------------
448 ULONG
449 STDMETHODCALLTYPE
450 CUSBRequest::GetTransferType()
451 {
452 //
453 // call internal implementation
454 //
455 return InternalGetTransferType();
456 }
457
458 USHORT
459 CUSBRequest::GetMaxPacketSize()
460 {
461 if (!m_EndpointDescriptor)
462 {
463 if (m_DeviceSpeed == UsbLowSpeed)
464 {
465 //
466 // control pipes use 8 bytes packets
467 //
468 return 8;
469 }
470 else
471 {
472 //
473 // must be full speed
474 //
475 ASSERT(m_DeviceSpeed == UsbFullSpeed);
476 return 64;
477 }
478 }
479
480 ASSERT(m_Irp);
481 ASSERT(m_EndpointDescriptor);
482
483 //
484 // return max packet size
485 //
486 return m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
487 }
488
489 UCHAR
490 STDMETHODCALLTYPE
491 CUSBRequest::GetInterval()
492 {
493 ASSERT(m_EndpointDescriptor);
494 ASSERT((m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
495
496 //
497 // return interrupt interval
498 //
499 return m_EndpointDescriptor->EndPointDescriptor.bInterval;
500 }
501
502 UCHAR
503 CUSBRequest::GetEndpointAddress()
504 {
505 if (!m_EndpointDescriptor)
506 {
507 //
508 // control request
509 //
510 return 0;
511 }
512
513 ASSERT(m_Irp);
514 ASSERT(m_EndpointDescriptor);
515
516 //
517 // endpoint number is between 1-15
518 //
519 return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0xF);
520 }
521
522 //----------------------------------------------------------------------------------------
523 ULONG
524 CUSBRequest::InternalGetTransferType()
525 {
526 ULONG TransferType;
527
528 //
529 // check if an irp is provided
530 //
531 if (m_Irp)
532 {
533 ASSERT(m_EndpointDescriptor);
534
535 //
536 // end point is defined in the low byte of bmAttributes
537 //
538 TransferType = (m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
539 }
540 else
541 {
542 //
543 // initialized with setup packet, must be a control transfer
544 //
545 TransferType = USB_ENDPOINT_TYPE_CONTROL;
546 }
547
548 //
549 // done
550 //
551 return TransferType;
552 }
553
554 UCHAR
555 CUSBRequest::InternalGetPidDirection()
556 {
557 if (m_EndpointDescriptor)
558 {
559 //
560 // end point direction is highest bit in bEndpointAddress
561 //
562 return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
563 }
564 else
565 {
566 //
567 // request arrives on the control pipe, extract direction from setup packet
568 //
569 ASSERT(m_SetupPacket);
570 return (m_SetupPacket->bmRequestType.B >> 7);
571 }
572 }
573
574 //----------------------------------------------------------------------------------------
575 UCHAR
576 STDMETHODCALLTYPE
577 CUSBRequest::GetDeviceAddress()
578 {
579 PIO_STACK_LOCATION IoStack;
580 PURB Urb;
581 PUSBDEVICE UsbDevice;
582
583 //
584 // check if there is an irp provided
585 //
586 if (!m_Irp)
587 {
588 //
589 // used provided address
590 //
591 return m_DeviceAddress;
592 }
593
594 //
595 // get current stack location
596 //
597 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
598
599 //
600 // get contained urb
601 //
602 Urb = (PURB)IoStack->Parameters.Others.Argument1;
603
604 //
605 // check if there is a pipe handle provided
606 //
607 if (Urb->UrbHeader.UsbdDeviceHandle)
608 {
609 //
610 // there is a device handle provided
611 //
612 UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
613
614 //
615 // return device address
616 //
617 return UsbDevice->GetDeviceAddress();
618 }
619
620 //
621 // no device handle provided, it is the host root bus
622 //
623 return 0;
624 }
625
626 VOID
627 CUSBRequest::FreeDescriptor(
628 POHCI_GENERAL_TD Descriptor)
629 {
630 if (Descriptor->BufferSize)
631 {
632 //
633 // free buffer
634 //
635 m_DmaManager->Release(Descriptor->BufferLogical, Descriptor->BufferSize);
636 }
637
638 //
639 // release descriptor
640 //
641 m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD));
642
643 }
644
645 //----------------------------------------------------------------------------------------
646 NTSTATUS
647 CUSBRequest::CreateIsochronousTransferDescriptor(
648 POHCI_ISO_TD* OutDescriptor,
649 ULONG FrameCount)
650 {
651 POHCI_ISO_TD Descriptor;
652 PHYSICAL_ADDRESS DescriptorAddress;
653 NTSTATUS Status;
654
655 //
656 // allocate transfer descriptor
657 //
658 Status = m_DmaManager->Allocate(sizeof(OHCI_ISO_TD), (PVOID*)&Descriptor, &DescriptorAddress);
659 if (!NT_SUCCESS(Status))
660 {
661 //
662 // no memory
663 //
664 return Status;
665 }
666
667 //
668 // initialize descriptor, hardware part
669 //
670 Descriptor->Flags = OHCI_ITD_SET_FRAME_COUNT(FrameCount) | OHCI_ITD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);// | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED);
671 Descriptor->BufferPhysical = 0;
672 Descriptor->NextPhysicalDescriptor = 0;
673 Descriptor->LastPhysicalByteAddress = 0;
674
675 //
676 // software part
677 //
678 Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
679 Descriptor->NextLogicalDescriptor = 0;
680
681 //
682 // store result
683 //
684 *OutDescriptor = Descriptor;
685
686 //
687 // done
688 //
689 return STATUS_SUCCESS;
690 }
691
692 NTSTATUS
693 CUSBRequest::BuildIsochronousEndpoint(
694 POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
695 {
696 POHCI_ISO_TD FirstDescriptor = NULL, PreviousDescriptor = NULL, CurrentDescriptor = NULL;
697 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
698 ULONG Index = 0, SubIndex, NumberOfPackets, PageOffset, Page;
699 NTSTATUS Status;
700 PVOID Buffer;
701 PIO_STACK_LOCATION IoStack;
702 PURB Urb;
703 PHYSICAL_ADDRESS Address;
704
705 //
706 // get current irp stack location
707 //
708 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
709
710 //
711 // sanity check
712 //
713 PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
714 PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
715 PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
716
717 //
718 // get urb
719 //
720 Urb = (PURB)IoStack->Parameters.Others.Argument1;
721 ASSERT(Urb);
722
723 //
724 // allocate endpoint descriptor
725 //
726 Status = AllocateEndpointDescriptor(&EndpointDescriptor);
727 if (!NT_SUCCESS(Status))
728 {
729 //
730 // failed to create setup descriptor
731 //
732 ASSERT(FALSE);
733 return Status;
734 }
735
736 //
737 // get buffer
738 //
739 Buffer = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
740 ASSERT(Buffer);
741
742 //
743 // FIXME: support requests which spans serveral pages
744 //
745 ASSERT(ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(m_TransferBufferMDL), MmGetMdlByteCount(m_TransferBufferMDL)) <= 2);
746
747 Status = m_DmaManager->Allocate(m_TransferBufferLength, &Buffer, &Address);
748 ASSERT(Status == STATUS_SUCCESS);
749
750
751 while(Index < Urb->UrbIsochronousTransfer.NumberOfPackets)
752 {
753 //
754 // get number of packets remaining
755 //
756 NumberOfPackets = min(Urb->UrbIsochronousTransfer.NumberOfPackets - Index, OHCI_ITD_NOFFSET);
757 //
758 // allocate iso descriptor
759 //
760 Status = CreateIsochronousTransferDescriptor(&CurrentDescriptor, NumberOfPackets);
761 if (!NT_SUCCESS(Status))
762 {
763 //
764 // FIXME: cleanup
765 // failed to allocate descriptor
766 //
767 ASSERT(FALSE);
768 return Status;
769 }
770
771 //
772 // get physical page
773 //
774 Page = MmGetPhysicalAddress(Buffer).LowPart;
775
776 //
777 // get page offset
778 //
779 PageOffset = BYTE_OFFSET(Page);
780
781 //
782 // initialize descriptor
783 //
784 CurrentDescriptor->BufferPhysical = Page - PageOffset;
785
786 for(SubIndex = 0; SubIndex < NumberOfPackets; SubIndex++)
787 {
788 //
789 // store buffer offset
790 //
791 CurrentDescriptor->Offset[SubIndex] = Urb->UrbIsochronousTransfer.IsoPacket[Index+SubIndex].Offset + PageOffset;
792 DPRINT("Index %lu PacketOffset %lu FinalOffset %lu\n", SubIndex+Index, Urb->UrbIsochronousTransfer.IsoPacket[Index+SubIndex].Offset, CurrentDescriptor->Offset[SubIndex]);
793 }
794
795 //
796 // increment packet offset
797 //
798 Index += NumberOfPackets;
799
800 //
801 // check if this is the last descriptor
802 //
803 if (Index == Urb->UrbIsochronousTransfer.NumberOfPackets)
804 {
805 //
806 // end of transfer
807 //
808 CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + PageOffset + m_TransferBufferLength - 1;
809 }
810 else
811 {
812 //
813 // use start address of next packet - 1
814 //
815 CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + PageOffset + Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset - 1;
816 }
817
818 //
819 // is there a previous descriptor
820 //
821 if (PreviousDescriptor)
822 {
823 //
824 // link descriptors
825 //
826 PreviousDescriptor->NextLogicalDescriptor = CurrentDescriptor;
827 PreviousDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
828 }
829 else
830 {
831 //
832 // first descriptor
833 //
834 FirstDescriptor = CurrentDescriptor;
835 }
836
837 //
838 // store as previous descriptor
839 //
840 PreviousDescriptor = CurrentDescriptor;
841 DPRINT("Current Descriptor %p Logical %lx StartAddress %x EndAddress %x\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, CurrentDescriptor->BufferPhysical, CurrentDescriptor->LastPhysicalByteAddress);
842
843 //
844 // fire interrupt as soon transfer is finished
845 //
846 CurrentDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
847 }
848
849 //
850 // clear interrupt mask for last transfer descriptor
851 //
852 CurrentDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
853
854 //
855 // fire interrupt as soon transfer is finished
856 //
857 CurrentDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
858
859 //
860 // set isochronous type
861 //
862 EndpointDescriptor->Flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
863
864 //
865 // now link descriptor to endpoint
866 //
867 EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
868 EndpointDescriptor->TailPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
869 EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
870
871 //
872 // store result
873 //
874 *OutEndpointDescriptor = EndpointDescriptor;
875
876 //
877 // done
878 //
879 return STATUS_SUCCESS;
880 }
881
882 //----------------------------------------------------------------------------------------
883 NTSTATUS
884 CUSBRequest::CreateGeneralTransferDescriptor(
885 POHCI_GENERAL_TD* OutDescriptor,
886 ULONG BufferSize)
887 {
888 POHCI_GENERAL_TD Descriptor;
889 PHYSICAL_ADDRESS DescriptorAddress;
890 NTSTATUS Status;
891
892 //
893 // allocate transfer descriptor
894 //
895 Status = m_DmaManager->Allocate(sizeof(OHCI_GENERAL_TD), (PVOID*)&Descriptor, &DescriptorAddress);
896 if (!NT_SUCCESS(Status))
897 {
898 //
899 // no memory
900 //
901 return Status;
902 }
903
904 //
905 // initialize descriptor, hardware part
906 //
907 Descriptor->Flags = 0;
908 Descriptor->BufferPhysical = 0;
909 Descriptor->NextPhysicalDescriptor = 0;
910 Descriptor->LastPhysicalByteAddress = 0;
911
912 //
913 // software part
914 //
915 Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
916 Descriptor->BufferSize = BufferSize;
917
918 if (BufferSize > 0)
919 {
920 //
921 // allocate buffer from dma
922 //
923 Status = m_DmaManager->Allocate(BufferSize, &Descriptor->BufferLogical, &DescriptorAddress);
924 if (!NT_SUCCESS(Status))
925 {
926 //
927 // no memory
928 //
929 m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD));
930 return Status;
931 }
932
933 //
934 // set physical address of buffer
935 //
936 Descriptor->BufferPhysical = DescriptorAddress.LowPart;
937 Descriptor->LastPhysicalByteAddress = Descriptor->BufferPhysical + BufferSize - 1;
938 }
939
940 //
941 // store result
942 //
943 *OutDescriptor = Descriptor;
944
945 //
946 // done
947 //
948 return STATUS_SUCCESS;
949 }
950
951 NTSTATUS
952 CUSBRequest::AllocateEndpointDescriptor(
953 OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor)
954 {
955 POHCI_ENDPOINT_DESCRIPTOR Descriptor;
956 PHYSICAL_ADDRESS DescriptorAddress;
957 NTSTATUS Status;
958
959 //
960 // allocate descriptor
961 //
962 Status = m_DmaManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR), (PVOID*)&Descriptor, &DescriptorAddress);
963 if (!NT_SUCCESS(Status))
964 {
965 //
966 // failed to allocate descriptor
967 //
968 return Status;
969 }
970
971 //
972 // intialize descriptor
973 //
974 Descriptor->Flags = OHCI_ENDPOINT_SKIP;
975
976 //
977 // append device address and endpoint number
978 //
979 Descriptor->Flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(GetDeviceAddress());
980 Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
981 Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
982
983 DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %lu\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
984
985 //
986 // is there an endpoint descriptor
987 //
988 if (m_EndpointDescriptor)
989 {
990 //
991 // check direction
992 //
993 if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress))
994 {
995 //
996 // direction out
997 //
998 Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_OUT;
999 }
1000 else
1001 {
1002 //
1003 // direction in
1004 //
1005 Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_IN;
1006 }
1007 }
1008 else
1009 {
1010 //
1011 // get it from transfer descriptor
1012 //
1013 Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_DESCRIPTOR;
1014 }
1015
1016 //
1017 // set type
1018 //
1019 if (m_DeviceSpeed == UsbFullSpeed)
1020 {
1021 //
1022 // device is full speed
1023 //
1024 Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED;
1025 }
1026 else if (m_DeviceSpeed == UsbLowSpeed)
1027 {
1028 //
1029 // device is full speed
1030 //
1031 Descriptor->Flags |= OHCI_ENDPOINT_LOW_SPEED;
1032 }
1033 else
1034 {
1035 //
1036 // error
1037 //
1038 ASSERT(FALSE);
1039 }
1040
1041 Descriptor->HeadPhysicalDescriptor = 0;
1042 Descriptor->NextPhysicalEndpoint = 0;
1043 Descriptor->TailPhysicalDescriptor = 0;
1044 Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
1045
1046 //
1047 // store result
1048 //
1049 *OutDescriptor = Descriptor;
1050
1051 //
1052 // done
1053 //
1054 return STATUS_SUCCESS;
1055 }
1056
1057 VOID
1058 CUSBRequest::InitDescriptor(
1059 IN POHCI_GENERAL_TD CurrentDescriptor,
1060 IN PVOID TransferBuffer,
1061 IN ULONG TransferBufferLength,
1062 IN UCHAR PidDirection)
1063 {
1064 ULONG Direction;
1065
1066 if (PidDirection)
1067 {
1068 //
1069 // input direction
1070 //
1071 Direction = OHCI_TD_DIRECTION_PID_IN;
1072 }
1073 else
1074 {
1075 //
1076 // output direction
1077 //
1078 Direction = OHCI_TD_DIRECTION_PID_OUT;
1079 }
1080
1081
1082 //
1083 // initialize descriptor
1084 //
1085 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;
1086
1087 //
1088 // store physical address of buffer
1089 //
1090 CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(TransferBuffer).LowPart;
1091 CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + TransferBufferLength - 1;
1092
1093 DPRINT("CurrentDescriptor %p Addr %x TransferBufferLength %lu\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, TransferBufferLength);
1094 }
1095
1096 NTSTATUS
1097 CUSBRequest::BuildTransferDescriptorChain(
1098 IN PVOID TransferBuffer,
1099 IN ULONG TransferBufferLength,
1100 IN UCHAR PidDirection,
1101 OUT POHCI_GENERAL_TD * OutFirstDescriptor,
1102 OUT POHCI_GENERAL_TD * OutLastDescriptor,
1103 OUT PULONG OutTransferBufferOffset)
1104 {
1105 POHCI_GENERAL_TD FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL;
1106 NTSTATUS Status;
1107 ULONG MaxLengthInPage, TransferBufferOffset = 0;
1108 ULONG MaxPacketSize = 0, TransferSize, CurrentSize;
1109
1110 //
1111 // for now use one page as maximum size
1112 //
1113 MaxPacketSize = PAGE_SIZE;
1114
1115 do
1116 {
1117 //
1118 // allocate transfer descriptor
1119 //
1120 Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0);
1121 if (!NT_SUCCESS(Status))
1122 {
1123 //
1124 // failed to allocate transfer descriptor
1125 //
1126 return STATUS_INSUFFICIENT_RESOURCES;
1127 }
1128
1129 if (MaxPacketSize)
1130 {
1131 //
1132 // transfer size is minimum available buffer or endpoint size
1133 //
1134 TransferSize = min(TransferBufferLength - TransferBufferOffset, MaxPacketSize);
1135 }
1136 else
1137 {
1138 //
1139 // use available buffer
1140 //
1141 TransferSize = TransferBufferLength - TransferBufferOffset;
1142 }
1143
1144 //
1145 // get page offset
1146 //
1147 MaxLengthInPage = PAGE_SIZE - BYTE_OFFSET(TransferBuffer);
1148
1149 //
1150 // get minimum from current page size
1151 //
1152 CurrentSize = min(TransferSize, MaxLengthInPage);
1153 ASSERT(CurrentSize);
1154
1155 //
1156 // now init the descriptor
1157 //
1158 InitDescriptor(CurrentDescriptor,
1159 (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset),
1160 CurrentSize,
1161 PidDirection);
1162
1163 //
1164 // adjust offset
1165 //
1166 TransferBufferOffset += CurrentSize;
1167
1168 //
1169 // is there a previous descriptor
1170 //
1171 if (LastDescriptor)
1172 {
1173 //
1174 // link descriptors
1175 //
1176 LastDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor;
1177 LastDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
1178 }
1179 else
1180 {
1181 //
1182 // it is the first descriptor
1183 //
1184 FirstDescriptor = CurrentDescriptor;
1185 }
1186
1187 if(TransferBufferLength == TransferBufferOffset)
1188 {
1189 //
1190 // end reached
1191 //
1192 break;
1193 }
1194
1195 }while(TRUE);
1196
1197 if (OutFirstDescriptor)
1198 {
1199 //
1200 // store first descriptor
1201 //
1202 *OutFirstDescriptor = FirstDescriptor;
1203 }
1204
1205 if (OutLastDescriptor)
1206 {
1207 //
1208 // store last descriptor
1209 //
1210 *OutLastDescriptor = CurrentDescriptor;
1211 }
1212
1213 if (OutTransferBufferOffset)
1214 {
1215 //
1216 // store offset
1217 //
1218 *OutTransferBufferOffset = TransferBufferOffset;
1219 }
1220
1221 //
1222 // done
1223 //
1224 return STATUS_SUCCESS;
1225 }
1226
1227
1228 NTSTATUS
1229 CUSBRequest::BuildBulkInterruptEndpoint(
1230 POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
1231 {
1232 POHCI_GENERAL_TD FirstDescriptor, LastDescriptor;
1233 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
1234 NTSTATUS Status;
1235 PVOID Base;
1236 ULONG ChainDescriptorLength;
1237
1238 //
1239 // sanity check
1240 //
1241 ASSERT(m_EndpointDescriptor);
1242
1243 //
1244 // allocate endpoint descriptor
1245 //
1246 Status = AllocateEndpointDescriptor(&EndpointDescriptor);
1247 if (!NT_SUCCESS(Status))
1248 {
1249 //
1250 // failed to create setup descriptor
1251 //
1252 return Status;
1253 }
1254
1255 ASSERT(m_TransferBufferMDL);
1256
1257 if (m_Base == NULL)
1258 {
1259 //
1260 // get buffer
1261 //
1262 m_Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
1263 }
1264
1265 //
1266 // Increase the size of last transfer, 0 in case this is the first
1267 //
1268 Base = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted);
1269
1270 //
1271 // sanity checks
1272 //
1273 ASSERT(m_EndpointDescriptor);
1274 ASSERT(Base);
1275
1276 //
1277 // use 2 * PAGE_SIZE at max for each new request
1278 //
1279 ULONG MaxTransferLength = min(1 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted);
1280 DPRINT("m_TransferBufferLength %lu m_TransferBufferLengthCompleted %lu DataToggle %x\n", m_TransferBufferLength, m_TransferBufferLengthCompleted, m_EndpointDescriptor->DataToggle);
1281
1282 //
1283 // build bulk transfer descriptor chain
1284 //
1285 Status = BuildTransferDescriptorChain(Base,
1286 MaxTransferLength,
1287 InternalGetPidDirection(),
1288 &FirstDescriptor,
1289 &LastDescriptor,
1290 &ChainDescriptorLength);
1291
1292 //
1293 // move to next offset
1294 //
1295 m_TransferBufferLengthCompleted += ChainDescriptorLength;
1296
1297 //
1298 // first descriptor has no carry bit
1299 //
1300 FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY;
1301
1302 //
1303 // apply data toggle
1304 //
1305 FirstDescriptor->Flags |= (m_EndpointDescriptor->DataToggle ? OHCI_TD_TOGGLE_1 : OHCI_TD_TOGGLE_0);
1306
1307 //
1308 // clear interrupt mask for last transfer descriptor
1309 //
1310 LastDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
1311
1312
1313 //
1314 // fire interrupt as soon transfer is finished
1315 //
1316 LastDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
1317
1318 //
1319 // now link descriptor to endpoint
1320 //
1321 EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
1322 EndpointDescriptor->TailPhysicalDescriptor = (FirstDescriptor == LastDescriptor ? 0 : LastDescriptor->PhysicalAddress.LowPart);
1323 EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
1324
1325 //
1326 // dump descriptor list
1327 //
1328 //DumpEndpointDescriptor(EndpointDescriptor);
1329
1330 //
1331 // store result
1332 //
1333 *OutEndpointDescriptor = EndpointDescriptor;
1334
1335 //
1336 // done
1337 //
1338 return STATUS_SUCCESS;
1339 }
1340
1341 VOID
1342 CUSBRequest::DumpEndpointDescriptor(
1343 POHCI_ENDPOINT_DESCRIPTOR Descriptor)
1344 {
1345 ULONG Count = 0;
1346 POHCI_GENERAL_TD GeneralDescriptor;
1347
1348 DPRINT1("EndpointDescriptor %p Addr %x\n", Descriptor, Descriptor->PhysicalAddress.LowPart);
1349 DPRINT1("EndpointDescriptor HeadPhysicalDescriptor %x HeadLogicalDescriptor %p\n", Descriptor->HeadPhysicalDescriptor, Descriptor->HeadLogicalDescriptor);
1350 DPRINT1("EndpointDescriptor TailPhysicalDescriptor %x\n", Descriptor->TailPhysicalDescriptor);
1351 DPRINT1("EndpointDescriptor NextDescriptor %p\n", Descriptor->NextDescriptor);
1352 DPRINT1("EndpointDescriptor NextPhysicalEndpoint %x\n", Descriptor->NextPhysicalEndpoint);
1353 DPRINT1("EndpointDescriptor Flags %x\n", Descriptor->Flags);
1354
1355
1356 GeneralDescriptor = (POHCI_GENERAL_TD)Descriptor->HeadLogicalDescriptor;
1357 while(GeneralDescriptor)
1358 {
1359 DPRINT1("Descriptor %lu Address %p Addr %x\n", Count, GeneralDescriptor, GeneralDescriptor->PhysicalAddress);
1360 DPRINT1("Descriptor %lu BufferLogical %p BufferPhysical %x\n", Count, GeneralDescriptor->BufferLogical, GeneralDescriptor->BufferPhysical);
1361 DPRINT1("Descriptor %lu BufferSize %lu\n", Count, GeneralDescriptor->BufferSize);
1362 DPRINT1("Descriptor %lu LastPhysicalByteAddress %x\n", Count, GeneralDescriptor->LastPhysicalByteAddress);
1363 DPRINT1("Descriptor %lu Flags %x\n", Count, GeneralDescriptor->Flags);
1364 DPRINT1("Descriptor %lu NextLogicalDescriptor %p NextPhysicalDescriptor %x\n", Count, GeneralDescriptor->NextLogicalDescriptor, GeneralDescriptor->NextPhysicalDescriptor);
1365
1366 Count++;
1367 GeneralDescriptor = (POHCI_GENERAL_TD)GeneralDescriptor->NextLogicalDescriptor;
1368 }
1369 }
1370
1371 NTSTATUS
1372 CUSBRequest::BuildControlTransferDescriptor(
1373 POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
1374 {
1375 POHCI_GENERAL_TD SetupDescriptor, StatusDescriptor, DataDescriptor = NULL, LastDescriptor;
1376 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
1377 NTSTATUS Status;
1378
1379 //
1380 // allocate endpoint descriptor
1381 //
1382 Status = AllocateEndpointDescriptor(&EndpointDescriptor);
1383 if (!NT_SUCCESS(Status))
1384 {
1385 //
1386 // failed to create setup descriptor
1387 //
1388 return Status;
1389 }
1390
1391 //
1392 // first allocate setup descriptor
1393 //
1394 Status = CreateGeneralTransferDescriptor(&SetupDescriptor, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1395 if (!NT_SUCCESS(Status))
1396 {
1397 //
1398 // failed to create setup descriptor
1399 //
1400 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1401 return Status;
1402 }
1403
1404 //
1405 // now create the status descriptor
1406 //
1407 Status = CreateGeneralTransferDescriptor(&StatusDescriptor, 0);
1408 if (!NT_SUCCESS(Status))
1409 {
1410 //
1411 // failed to create status descriptor
1412 //
1413 FreeDescriptor(SetupDescriptor);
1414 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1415 return Status;
1416 }
1417
1418 //
1419 // finally create the last descriptor
1420 //
1421 Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0);
1422 if (!NT_SUCCESS(Status))
1423 {
1424 //
1425 // failed to create status descriptor
1426 //
1427 FreeDescriptor(SetupDescriptor);
1428 FreeDescriptor(StatusDescriptor);
1429 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1430 return Status;
1431 }
1432
1433 //
1434 // initialize setup descriptor
1435 //
1436 SetupDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING | 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);
1437
1438 //
1439 // initialize status descriptor
1440 //
1441 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);
1442
1443 if (m_SetupPacket)
1444 {
1445 //
1446 // copy setup packet
1447 //
1448 RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1449 }
1450 else
1451 {
1452 //
1453 // generate setup packet from urb
1454 //
1455 ASSERT(FALSE);
1456 }
1457
1458 if (m_TransferBufferLength)
1459 {
1460 //
1461 // FIXME: support more than one data descriptor
1462 //
1463 ASSERT(m_TransferBufferLength < 8192);
1464
1465 //
1466 // now create the data descriptor
1467 //
1468 Status = CreateGeneralTransferDescriptor(&DataDescriptor, 0);
1469 if (!NT_SUCCESS(Status))
1470 {
1471 //
1472 // failed to create status descriptor
1473 //
1474 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1475 FreeDescriptor(SetupDescriptor);
1476 FreeDescriptor(StatusDescriptor);
1477 return Status;
1478 }
1479
1480 //
1481 // initialize data descriptor
1482 //
1483 DataDescriptor->Flags = 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_TOGGLE_1;
1484
1485 //
1486 // setup pid direction
1487 //
1488 DataDescriptor->Flags |= InternalGetPidDirection() == TRUE ? OHCI_TD_DIRECTION_PID_IN : OHCI_TD_DIRECTION_PID_OUT;
1489
1490 //
1491 // use short packets
1492 //
1493 DataDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
1494
1495 //
1496 // store physical address of buffer
1497 //
1498 DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart;
1499 DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1;
1500
1501 //
1502 // flip status pid direction
1503 //
1504 StatusDescriptor->Flags |= InternalGetPidDirection() == TRUE ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN;
1505
1506 //
1507 // link setup descriptor to data descriptor
1508 //
1509 SetupDescriptor->NextPhysicalDescriptor = DataDescriptor->PhysicalAddress.LowPart;
1510 SetupDescriptor->NextLogicalDescriptor = DataDescriptor;
1511
1512 //
1513 // link data descriptor to status descriptor
1514 // FIXME: check if there are more data descriptors
1515 //
1516 DataDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart;
1517 DataDescriptor->NextLogicalDescriptor = StatusDescriptor;
1518
1519 //
1520 // link status descriptor to last descriptor
1521 //
1522 StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1523 StatusDescriptor->NextLogicalDescriptor = LastDescriptor;
1524 }
1525 else
1526 {
1527 //
1528 // status descriptor is always in
1529 //
1530 StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
1531
1532 //
1533 // link setup descriptor to status descriptor
1534 //
1535 SetupDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart;
1536 SetupDescriptor->NextLogicalDescriptor = StatusDescriptor;
1537 //
1538 // link status descriptor to last descriptor
1539 //
1540 StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1541 StatusDescriptor->NextLogicalDescriptor = LastDescriptor;
1542 }
1543
1544 //
1545 // now link descriptor to endpoint
1546 //
1547 EndpointDescriptor->HeadPhysicalDescriptor = SetupDescriptor->PhysicalAddress.LowPart;
1548 EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1549 EndpointDescriptor->HeadLogicalDescriptor = SetupDescriptor;
1550
1551 //
1552 // store result
1553 //
1554 *OutEndpointDescriptor = EndpointDescriptor;
1555
1556 //
1557 // dump descriptor
1558 //
1559 //DumpEndpointDescriptor(EndpointDescriptor);
1560
1561 //
1562 // done
1563 //
1564 return STATUS_SUCCESS;
1565 }
1566
1567 //----------------------------------------------------------------------------------------
1568 NTSTATUS
1569 STDMETHODCALLTYPE
1570 CUSBRequest::GetEndpointDescriptor(
1571 struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
1572 {
1573 ULONG TransferType;
1574 NTSTATUS Status;
1575
1576
1577 //
1578 // get transfer type
1579 //
1580 TransferType = InternalGetTransferType();
1581
1582 //
1583 // build request depending on type
1584 //
1585 switch(TransferType)
1586 {
1587 case USB_ENDPOINT_TYPE_CONTROL:
1588 Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
1589 break;
1590 case USB_ENDPOINT_TYPE_BULK:
1591 case USB_ENDPOINT_TYPE_INTERRUPT:
1592 Status = BuildBulkInterruptEndpoint(OutDescriptor);
1593 break;
1594 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
1595 Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
1596 break;
1597 default:
1598 PC_ASSERT(FALSE);
1599 Status = STATUS_NOT_IMPLEMENTED;
1600 break;
1601 }
1602
1603
1604
1605 if (NT_SUCCESS(Status))
1606 {
1607 //
1608 // store queue head
1609 //
1610 //m_QueueHead = *OutDescriptor;
1611
1612 //
1613 // store request object
1614 //
1615 (*OutDescriptor)->Request = PVOID(this);
1616 }
1617
1618 //
1619 // done
1620 //
1621 return Status;
1622 }
1623
1624 //----------------------------------------------------------------------------------------
1625 VOID
1626 STDMETHODCALLTYPE
1627 CUSBRequest::GetResultStatus(
1628 OUT OPTIONAL NTSTATUS * NtStatusCode,
1629 OUT OPTIONAL PULONG UrbStatusCode)
1630 {
1631 //
1632 // sanity check
1633 //
1634 PC_ASSERT(m_CompletionEvent);
1635
1636 //
1637 // wait for the operation to complete
1638 //
1639 KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
1640
1641 //
1642 // copy status
1643 //
1644 if (NtStatusCode)
1645 {
1646 *NtStatusCode = m_NtStatusCode;
1647 }
1648
1649 //
1650 // copy urb status
1651 //
1652 if (UrbStatusCode)
1653 {
1654 *UrbStatusCode = m_UrbStatusCode;
1655 }
1656
1657 }
1658
1659 VOID
1660 STDMETHODCALLTYPE
1661 CUSBRequest::FreeEndpointDescriptor(
1662 struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
1663 {
1664 POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
1665 POHCI_ISO_TD IsoTransferDescriptor, IsoNextTransferDescriptor;
1666 ULONG Index, PacketCount;
1667
1668 DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
1669
1670 //
1671 // check for errors
1672 //
1673 CheckError(OutDescriptor);
1674
1675
1676 if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
1677 {
1678 //
1679 // get first iso transfer descriptor
1680 //
1681 IsoTransferDescriptor = (POHCI_ISO_TD)OutDescriptor->HeadLogicalDescriptor;
1682
1683 //
1684 // release endpoint descriptor
1685 //
1686 m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1687
1688 while(IsoTransferDescriptor)
1689 {
1690 //
1691 // get next
1692 //
1693 IsoNextTransferDescriptor = IsoTransferDescriptor->NextLogicalDescriptor;
1694
1695 //
1696 // get packet count
1697 //
1698 PacketCount = OHCI_ITD_GET_FRAME_COUNT(IsoTransferDescriptor->Flags);
1699
1700 DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x PacketCount %lu\n", IsoTransferDescriptor, IsoTransferDescriptor->PhysicalAddress.LowPart, IsoTransferDescriptor->BufferPhysical, IsoTransferDescriptor->LastPhysicalByteAddress, PacketCount);
1701
1702 for(Index = 0; Index < PacketCount; Index++)
1703 {
1704 DPRINT("PSW Index %lu Value %x\n", Index, IsoTransferDescriptor->Offset[Index]);
1705 }
1706
1707 //
1708 // release descriptor
1709 //
1710 m_DmaManager->Release(IsoTransferDescriptor, sizeof(OHCI_ISO_TD));
1711
1712 //
1713 // move to next
1714 //
1715 IsoTransferDescriptor = IsoNextTransferDescriptor;
1716 }
1717 }
1718 else
1719 {
1720 //
1721 // get first general transfer descriptor
1722 //
1723 TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
1724
1725 //
1726 // release endpoint descriptor
1727 //
1728 m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1729
1730 while(TransferDescriptor)
1731 {
1732 //
1733 // get next
1734 //
1735 NextTransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
1736
1737 //
1738 // is there a buffer associated
1739 //
1740 if (TransferDescriptor->BufferSize)
1741 {
1742 //
1743 // release buffer
1744 //
1745 m_DmaManager->Release(TransferDescriptor->BufferLogical, TransferDescriptor->BufferSize);
1746 }
1747
1748 DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x\n", TransferDescriptor, TransferDescriptor->PhysicalAddress.LowPart, TransferDescriptor->BufferPhysical, TransferDescriptor->LastPhysicalByteAddress);
1749
1750 //
1751 // release descriptor
1752 //
1753 m_DmaManager->Release(TransferDescriptor, sizeof(OHCI_GENERAL_TD));
1754
1755 //
1756 // move to next
1757 //
1758 TransferDescriptor = NextTransferDescriptor;
1759 }
1760 }
1761
1762 }
1763
1764 VOID
1765 CUSBRequest::CheckError(
1766 struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
1767 {
1768 POHCI_GENERAL_TD TransferDescriptor;
1769 ULONG ConditionCode;
1770 PURB Urb;
1771 PIO_STACK_LOCATION IoStack;
1772
1773
1774 //
1775 // set status code
1776 //
1777 m_NtStatusCode = STATUS_SUCCESS;
1778 m_UrbStatusCode = USBD_STATUS_SUCCESS;
1779
1780
1781 if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
1782 {
1783 //
1784 // FIXME: handle isochronous support
1785 //
1786 ASSERT(FALSE);
1787 }
1788 else
1789 {
1790 //
1791 // get first general transfer descriptor
1792 //
1793 TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
1794
1795 if (m_EndpointDescriptor != NULL)
1796 {
1797 //
1798 // update data toggle
1799 //
1800 m_EndpointDescriptor->DataToggle = (OutDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_TOGGLE_CARRY);
1801 }
1802
1803 while(TransferDescriptor)
1804 {
1805 //
1806 // get condition code
1807 //
1808 ConditionCode = OHCI_TD_GET_CONDITION_CODE(TransferDescriptor->Flags);
1809 if (ConditionCode != OHCI_TD_CONDITION_NO_ERROR)
1810 {
1811 //
1812 // FIXME status code
1813 //
1814 m_NtStatusCode = STATUS_UNSUCCESSFUL;
1815
1816 switch(ConditionCode)
1817 {
1818 case OHCI_TD_CONDITION_CRC_ERROR:
1819 DPRINT1("OHCI_TD_CONDITION_CRC_ERROR detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1820 m_UrbStatusCode = USBD_STATUS_CRC;
1821 break;
1822 case OHCI_TD_CONDITION_BIT_STUFFING:
1823 DPRINT1("OHCI_TD_CONDITION_BIT_STUFFING detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1824 m_UrbStatusCode = USBD_STATUS_BTSTUFF;
1825 break;
1826 case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
1827 DPRINT1("OHCI_TD_CONDITION_TOGGLE_MISMATCH detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1828 m_UrbStatusCode = USBD_STATUS_DATA_TOGGLE_MISMATCH;
1829 break;
1830 case OHCI_TD_CONDITION_STALL:
1831 DPRINT1("OHCI_TD_CONDITION_STALL detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1832 m_UrbStatusCode = USBD_STATUS_STALL_PID;
1833 break;
1834 case OHCI_TD_CONDITION_NO_RESPONSE:
1835 DPRINT1("OHCI_TD_CONDITION_NO_RESPONSE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1836 m_UrbStatusCode = USBD_STATUS_DEV_NOT_RESPONDING;
1837 break;
1838 case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
1839 DPRINT1("OHCI_TD_CONDITION_PID_CHECK_FAILURE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1840 m_UrbStatusCode = USBD_STATUS_PID_CHECK_FAILURE;
1841 break;
1842 case OHCI_TD_CONDITION_UNEXPECTED_PID:
1843 DPRINT1("OHCI_TD_CONDITION_UNEXPECTED_PID detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1844 m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
1845 break;
1846 case OHCI_TD_CONDITION_DATA_OVERRUN:
1847 DPRINT1("OHCI_TD_CONDITION_DATA_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1848 m_UrbStatusCode = USBD_STATUS_DATA_OVERRUN;
1849 break;
1850 case OHCI_TD_CONDITION_DATA_UNDERRUN:
1851 if (m_Irp)
1852 {
1853 //
1854 // get current irp stack location
1855 //
1856 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1857
1858 //
1859 // get urb
1860 //
1861 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1862
1863 if(Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
1864 {
1865 //
1866 // short packets are ok
1867 //
1868 ASSERT(Urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER);
1869 m_NtStatusCode = STATUS_SUCCESS;
1870 break;
1871 }
1872 }
1873 DPRINT1("OHCI_TD_CONDITION_DATA_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1874 m_UrbStatusCode = USBD_STATUS_DATA_UNDERRUN;
1875 break;
1876 case OHCI_TD_CONDITION_BUFFER_OVERRUN:
1877 DPRINT1("OHCI_TD_CONDITION_BUFFER_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1878 m_UrbStatusCode = USBD_STATUS_BUFFER_OVERRUN;
1879 break;
1880 case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
1881 DPRINT1("OHCI_TD_CONDITION_BUFFER_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1882 m_UrbStatusCode = USBD_STATUS_BUFFER_UNDERRUN;
1883 break;
1884 }
1885 }
1886
1887 //
1888 // get next
1889 //
1890 TransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
1891 }
1892 }
1893 }
1894
1895 VOID
1896 STDMETHODCALLTYPE
1897 CUSBRequest::CompletionCallback()
1898 {
1899 PIO_STACK_LOCATION IoStack;
1900 PURB Urb;
1901
1902 DPRINT("CUSBRequest::CompletionCallback\n");
1903
1904 if (m_Irp)
1905 {
1906 //
1907 // set irp completion status
1908 //
1909 m_Irp->IoStatus.Status = m_NtStatusCode;
1910
1911 //
1912 // get current irp stack location
1913 //
1914 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1915
1916 //
1917 // get urb
1918 //
1919 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1920
1921 //
1922 // store urb status
1923 //
1924 Urb->UrbHeader.Status = m_UrbStatusCode;
1925
1926 //
1927 // Check if the MDL was created
1928 //
1929 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
1930 {
1931 //
1932 // Free Mdl
1933 //
1934 IoFreeMdl(m_TransferBufferMDL);
1935 }
1936
1937 //
1938 // FIXME calculate length
1939 //
1940
1941 //
1942 // complete request
1943 //
1944 IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
1945 }
1946 else
1947 {
1948 //
1949 // signal completion event
1950 //
1951 PC_ASSERT(m_CompletionEvent);
1952 KeSetEvent(m_CompletionEvent, 0, FALSE);
1953 }
1954 }
1955
1956 //-----------------------------------------------------------------------------------------
1957 NTSTATUS
1958 NTAPI
1959 InternalCreateUSBRequest(
1960 PUSBREQUEST *OutRequest)
1961 {
1962 PUSBREQUEST This;
1963
1964 //
1965 // allocate requests
1966 //
1967 This = new(NonPagedPool, TAG_USBOHCI) CUSBRequest(0);
1968 if (!This)
1969 {
1970 //
1971 // failed to allocate
1972 //
1973 return STATUS_INSUFFICIENT_RESOURCES;
1974 }
1975
1976 //
1977 // add reference count
1978 //
1979 This->AddRef();
1980
1981 //
1982 // return result
1983 //
1984 *OutRequest = (PUSBREQUEST)This;
1985
1986 //
1987 // done
1988 //
1989 return STATUS_SUCCESS;
1990 }