[USBSTOR]
[reactos.git] / reactos / 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 #include "usbohci.h"
12
13 #define NDEBUG
14 #include <debug.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 several 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 // initialize 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 if (!NT_SUCCESS(Status))
1292 {
1293 //
1294 // failed to build transfer descriptor chain
1295 //
1296 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1297 return Status;
1298 }
1299
1300 //
1301 // move to next offset
1302 //
1303 m_TransferBufferLengthCompleted += ChainDescriptorLength;
1304
1305 //
1306 // first descriptor has no carry bit
1307 //
1308 FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY;
1309
1310 //
1311 // apply data toggle
1312 //
1313 FirstDescriptor->Flags |= (m_EndpointDescriptor->DataToggle ? OHCI_TD_TOGGLE_1 : OHCI_TD_TOGGLE_0);
1314
1315 //
1316 // clear interrupt mask for last transfer descriptor
1317 //
1318 LastDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
1319
1320
1321 //
1322 // fire interrupt as soon transfer is finished
1323 //
1324 LastDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
1325
1326 //
1327 // now link descriptor to endpoint
1328 //
1329 EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
1330 EndpointDescriptor->TailPhysicalDescriptor = (FirstDescriptor == LastDescriptor ? 0 : LastDescriptor->PhysicalAddress.LowPart);
1331 EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
1332
1333 //
1334 // dump descriptor list
1335 //
1336 //DumpEndpointDescriptor(EndpointDescriptor);
1337
1338 //
1339 // store result
1340 //
1341 *OutEndpointDescriptor = EndpointDescriptor;
1342
1343 //
1344 // done
1345 //
1346 return STATUS_SUCCESS;
1347 }
1348
1349 VOID
1350 CUSBRequest::DumpEndpointDescriptor(
1351 POHCI_ENDPOINT_DESCRIPTOR Descriptor)
1352 {
1353 ULONG Count = 0;
1354 POHCI_GENERAL_TD GeneralDescriptor;
1355
1356 DPRINT1("EndpointDescriptor %p Addr %x\n", Descriptor, Descriptor->PhysicalAddress.LowPart);
1357 DPRINT1("EndpointDescriptor HeadPhysicalDescriptor %x HeadLogicalDescriptor %p\n", Descriptor->HeadPhysicalDescriptor, Descriptor->HeadLogicalDescriptor);
1358 DPRINT1("EndpointDescriptor TailPhysicalDescriptor %x\n", Descriptor->TailPhysicalDescriptor);
1359 DPRINT1("EndpointDescriptor NextDescriptor %p\n", Descriptor->NextDescriptor);
1360 DPRINT1("EndpointDescriptor NextPhysicalEndpoint %x\n", Descriptor->NextPhysicalEndpoint);
1361 DPRINT1("EndpointDescriptor Flags %x\n", Descriptor->Flags);
1362
1363
1364 GeneralDescriptor = (POHCI_GENERAL_TD)Descriptor->HeadLogicalDescriptor;
1365 while(GeneralDescriptor)
1366 {
1367 DPRINT1("Descriptor %lu Address %p Addr %x\n", Count, GeneralDescriptor, GeneralDescriptor->PhysicalAddress);
1368 DPRINT1("Descriptor %lu BufferLogical %p BufferPhysical %x\n", Count, GeneralDescriptor->BufferLogical, GeneralDescriptor->BufferPhysical);
1369 DPRINT1("Descriptor %lu BufferSize %lu\n", Count, GeneralDescriptor->BufferSize);
1370 DPRINT1("Descriptor %lu LastPhysicalByteAddress %x\n", Count, GeneralDescriptor->LastPhysicalByteAddress);
1371 DPRINT1("Descriptor %lu Flags %x\n", Count, GeneralDescriptor->Flags);
1372 DPRINT1("Descriptor %lu NextLogicalDescriptor %p NextPhysicalDescriptor %x\n", Count, GeneralDescriptor->NextLogicalDescriptor, GeneralDescriptor->NextPhysicalDescriptor);
1373
1374 Count++;
1375 GeneralDescriptor = (POHCI_GENERAL_TD)GeneralDescriptor->NextLogicalDescriptor;
1376 }
1377 }
1378
1379 NTSTATUS
1380 CUSBRequest::BuildControlTransferDescriptor(
1381 POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
1382 {
1383 POHCI_GENERAL_TD SetupDescriptor, StatusDescriptor, DataDescriptor = NULL, LastDescriptor;
1384 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
1385 NTSTATUS Status;
1386
1387 //
1388 // allocate endpoint descriptor
1389 //
1390 Status = AllocateEndpointDescriptor(&EndpointDescriptor);
1391 if (!NT_SUCCESS(Status))
1392 {
1393 //
1394 // failed to create setup descriptor
1395 //
1396 return Status;
1397 }
1398
1399 //
1400 // first allocate setup descriptor
1401 //
1402 Status = CreateGeneralTransferDescriptor(&SetupDescriptor, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1403 if (!NT_SUCCESS(Status))
1404 {
1405 //
1406 // failed to create setup descriptor
1407 //
1408 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1409 return Status;
1410 }
1411
1412 //
1413 // now create the status descriptor
1414 //
1415 Status = CreateGeneralTransferDescriptor(&StatusDescriptor, 0);
1416 if (!NT_SUCCESS(Status))
1417 {
1418 //
1419 // failed to create status descriptor
1420 //
1421 FreeDescriptor(SetupDescriptor);
1422 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1423 return Status;
1424 }
1425
1426 //
1427 // finally create the last descriptor
1428 //
1429 Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0);
1430 if (!NT_SUCCESS(Status))
1431 {
1432 //
1433 // failed to create status descriptor
1434 //
1435 FreeDescriptor(SetupDescriptor);
1436 FreeDescriptor(StatusDescriptor);
1437 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1438 return Status;
1439 }
1440
1441 //
1442 // initialize setup descriptor
1443 //
1444 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);
1445
1446 //
1447 // initialize status descriptor
1448 //
1449 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);
1450
1451 if (m_SetupPacket)
1452 {
1453 //
1454 // copy setup packet
1455 //
1456 RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1457 }
1458 else
1459 {
1460 //
1461 // generate setup packet from urb
1462 //
1463 ASSERT(FALSE);
1464 }
1465
1466 if (m_TransferBufferLength)
1467 {
1468 //
1469 // FIXME: support more than one data descriptor
1470 //
1471 ASSERT(m_TransferBufferLength < 8192);
1472
1473 //
1474 // now create the data descriptor
1475 //
1476 Status = CreateGeneralTransferDescriptor(&DataDescriptor, 0);
1477 if (!NT_SUCCESS(Status))
1478 {
1479 //
1480 // failed to create status descriptor
1481 //
1482 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1483 FreeDescriptor(SetupDescriptor);
1484 FreeDescriptor(StatusDescriptor);
1485 return Status;
1486 }
1487
1488 //
1489 // initialize data descriptor
1490 //
1491 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;
1492
1493 //
1494 // setup pid direction
1495 //
1496 DataDescriptor->Flags |= InternalGetPidDirection() == TRUE ? OHCI_TD_DIRECTION_PID_IN : OHCI_TD_DIRECTION_PID_OUT;
1497
1498 //
1499 // use short packets
1500 //
1501 DataDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
1502
1503 //
1504 // store physical address of buffer
1505 //
1506 DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart;
1507 DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1;
1508
1509 //
1510 // flip status pid direction
1511 //
1512 StatusDescriptor->Flags |= InternalGetPidDirection() == TRUE ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN;
1513
1514 //
1515 // link setup descriptor to data descriptor
1516 //
1517 SetupDescriptor->NextPhysicalDescriptor = DataDescriptor->PhysicalAddress.LowPart;
1518 SetupDescriptor->NextLogicalDescriptor = DataDescriptor;
1519
1520 //
1521 // link data descriptor to status descriptor
1522 // FIXME: check if there are more data descriptors
1523 //
1524 DataDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart;
1525 DataDescriptor->NextLogicalDescriptor = StatusDescriptor;
1526
1527 //
1528 // link status descriptor to last descriptor
1529 //
1530 StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1531 StatusDescriptor->NextLogicalDescriptor = LastDescriptor;
1532 }
1533 else
1534 {
1535 //
1536 // status descriptor is always in
1537 //
1538 StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
1539
1540 //
1541 // link setup descriptor to status descriptor
1542 //
1543 SetupDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart;
1544 SetupDescriptor->NextLogicalDescriptor = StatusDescriptor;
1545 //
1546 // link status descriptor to last descriptor
1547 //
1548 StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1549 StatusDescriptor->NextLogicalDescriptor = LastDescriptor;
1550 }
1551
1552 //
1553 // now link descriptor to endpoint
1554 //
1555 EndpointDescriptor->HeadPhysicalDescriptor = SetupDescriptor->PhysicalAddress.LowPart;
1556 EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1557 EndpointDescriptor->HeadLogicalDescriptor = SetupDescriptor;
1558
1559 //
1560 // store result
1561 //
1562 *OutEndpointDescriptor = EndpointDescriptor;
1563
1564 //
1565 // dump descriptor
1566 //
1567 //DumpEndpointDescriptor(EndpointDescriptor);
1568
1569 //
1570 // done
1571 //
1572 return STATUS_SUCCESS;
1573 }
1574
1575 //----------------------------------------------------------------------------------------
1576 NTSTATUS
1577 STDMETHODCALLTYPE
1578 CUSBRequest::GetEndpointDescriptor(
1579 struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
1580 {
1581 ULONG TransferType;
1582 NTSTATUS Status;
1583
1584
1585 //
1586 // get transfer type
1587 //
1588 TransferType = InternalGetTransferType();
1589
1590 //
1591 // build request depending on type
1592 //
1593 switch(TransferType)
1594 {
1595 case USB_ENDPOINT_TYPE_CONTROL:
1596 Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
1597 break;
1598 case USB_ENDPOINT_TYPE_BULK:
1599 case USB_ENDPOINT_TYPE_INTERRUPT:
1600 Status = BuildBulkInterruptEndpoint(OutDescriptor);
1601 break;
1602 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
1603 Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
1604 break;
1605 default:
1606 PC_ASSERT(FALSE);
1607 Status = STATUS_NOT_IMPLEMENTED;
1608 break;
1609 }
1610
1611
1612
1613 if (NT_SUCCESS(Status))
1614 {
1615 //
1616 // store queue head
1617 //
1618 //m_QueueHead = *OutDescriptor;
1619
1620 //
1621 // store request object
1622 //
1623 (*OutDescriptor)->Request = PVOID(this);
1624 }
1625
1626 //
1627 // done
1628 //
1629 return Status;
1630 }
1631
1632 //----------------------------------------------------------------------------------------
1633 VOID
1634 STDMETHODCALLTYPE
1635 CUSBRequest::GetResultStatus(
1636 OUT OPTIONAL NTSTATUS * NtStatusCode,
1637 OUT OPTIONAL PULONG UrbStatusCode)
1638 {
1639 //
1640 // sanity check
1641 //
1642 PC_ASSERT(m_CompletionEvent);
1643
1644 //
1645 // wait for the operation to complete
1646 //
1647 KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
1648
1649 //
1650 // copy status
1651 //
1652 if (NtStatusCode)
1653 {
1654 *NtStatusCode = m_NtStatusCode;
1655 }
1656
1657 //
1658 // copy urb status
1659 //
1660 if (UrbStatusCode)
1661 {
1662 *UrbStatusCode = m_UrbStatusCode;
1663 }
1664
1665 }
1666
1667 VOID
1668 STDMETHODCALLTYPE
1669 CUSBRequest::FreeEndpointDescriptor(
1670 struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
1671 {
1672 POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
1673 POHCI_ISO_TD IsoTransferDescriptor, IsoNextTransferDescriptor;
1674 ULONG Index, PacketCount;
1675
1676 DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
1677
1678 //
1679 // check for errors
1680 //
1681 CheckError(OutDescriptor);
1682
1683
1684 if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
1685 {
1686 //
1687 // get first iso transfer descriptor
1688 //
1689 IsoTransferDescriptor = (POHCI_ISO_TD)OutDescriptor->HeadLogicalDescriptor;
1690
1691 //
1692 // release endpoint descriptor
1693 //
1694 m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1695
1696 while(IsoTransferDescriptor)
1697 {
1698 //
1699 // get next
1700 //
1701 IsoNextTransferDescriptor = IsoTransferDescriptor->NextLogicalDescriptor;
1702
1703 //
1704 // get packet count
1705 //
1706 PacketCount = OHCI_ITD_GET_FRAME_COUNT(IsoTransferDescriptor->Flags);
1707
1708 DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x PacketCount %lu\n", IsoTransferDescriptor, IsoTransferDescriptor->PhysicalAddress.LowPart, IsoTransferDescriptor->BufferPhysical, IsoTransferDescriptor->LastPhysicalByteAddress, PacketCount);
1709
1710 for(Index = 0; Index < PacketCount; Index++)
1711 {
1712 DPRINT("PSW Index %lu Value %x\n", Index, IsoTransferDescriptor->Offset[Index]);
1713 }
1714
1715 //
1716 // release descriptor
1717 //
1718 m_DmaManager->Release(IsoTransferDescriptor, sizeof(OHCI_ISO_TD));
1719
1720 //
1721 // move to next
1722 //
1723 IsoTransferDescriptor = IsoNextTransferDescriptor;
1724 }
1725 }
1726 else
1727 {
1728 //
1729 // get first general transfer descriptor
1730 //
1731 TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
1732
1733 //
1734 // release endpoint descriptor
1735 //
1736 m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1737
1738 while(TransferDescriptor)
1739 {
1740 //
1741 // get next
1742 //
1743 NextTransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
1744
1745 //
1746 // is there a buffer associated
1747 //
1748 if (TransferDescriptor->BufferSize)
1749 {
1750 //
1751 // release buffer
1752 //
1753 m_DmaManager->Release(TransferDescriptor->BufferLogical, TransferDescriptor->BufferSize);
1754 }
1755
1756 DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x\n", TransferDescriptor, TransferDescriptor->PhysicalAddress.LowPart, TransferDescriptor->BufferPhysical, TransferDescriptor->LastPhysicalByteAddress);
1757
1758 //
1759 // release descriptor
1760 //
1761 m_DmaManager->Release(TransferDescriptor, sizeof(OHCI_GENERAL_TD));
1762
1763 //
1764 // move to next
1765 //
1766 TransferDescriptor = NextTransferDescriptor;
1767 }
1768 }
1769
1770 }
1771
1772 VOID
1773 CUSBRequest::CheckError(
1774 struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
1775 {
1776 POHCI_GENERAL_TD TransferDescriptor;
1777 ULONG ConditionCode;
1778 PURB Urb;
1779 PIO_STACK_LOCATION IoStack;
1780
1781
1782 //
1783 // set status code
1784 //
1785 m_NtStatusCode = STATUS_SUCCESS;
1786 m_UrbStatusCode = USBD_STATUS_SUCCESS;
1787
1788
1789 if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
1790 {
1791 //
1792 // FIXME: handle isochronous support
1793 //
1794 ASSERT(FALSE);
1795 }
1796 else
1797 {
1798 //
1799 // get first general transfer descriptor
1800 //
1801 TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
1802
1803 if (m_EndpointDescriptor != NULL)
1804 {
1805 //
1806 // update data toggle
1807 //
1808 m_EndpointDescriptor->DataToggle = (OutDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_TOGGLE_CARRY);
1809 }
1810
1811 while(TransferDescriptor)
1812 {
1813 //
1814 // get condition code
1815 //
1816 ConditionCode = OHCI_TD_GET_CONDITION_CODE(TransferDescriptor->Flags);
1817 if (ConditionCode != OHCI_TD_CONDITION_NO_ERROR)
1818 {
1819 //
1820 // FIXME status code
1821 //
1822 m_NtStatusCode = STATUS_UNSUCCESSFUL;
1823
1824 switch(ConditionCode)
1825 {
1826 case OHCI_TD_CONDITION_CRC_ERROR:
1827 DPRINT1("OHCI_TD_CONDITION_CRC_ERROR detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1828 m_UrbStatusCode = USBD_STATUS_CRC;
1829 break;
1830 case OHCI_TD_CONDITION_BIT_STUFFING:
1831 DPRINT1("OHCI_TD_CONDITION_BIT_STUFFING detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1832 m_UrbStatusCode = USBD_STATUS_BTSTUFF;
1833 break;
1834 case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
1835 DPRINT1("OHCI_TD_CONDITION_TOGGLE_MISMATCH detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1836 m_UrbStatusCode = USBD_STATUS_DATA_TOGGLE_MISMATCH;
1837 break;
1838 case OHCI_TD_CONDITION_STALL:
1839 DPRINT1("OHCI_TD_CONDITION_STALL detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1840 m_UrbStatusCode = USBD_STATUS_STALL_PID;
1841 break;
1842 case OHCI_TD_CONDITION_NO_RESPONSE:
1843 DPRINT1("OHCI_TD_CONDITION_NO_RESPONSE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1844 m_UrbStatusCode = USBD_STATUS_DEV_NOT_RESPONDING;
1845 break;
1846 case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
1847 DPRINT1("OHCI_TD_CONDITION_PID_CHECK_FAILURE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1848 m_UrbStatusCode = USBD_STATUS_PID_CHECK_FAILURE;
1849 break;
1850 case OHCI_TD_CONDITION_UNEXPECTED_PID:
1851 DPRINT1("OHCI_TD_CONDITION_UNEXPECTED_PID detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1852 m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
1853 break;
1854 case OHCI_TD_CONDITION_DATA_OVERRUN:
1855 DPRINT1("OHCI_TD_CONDITION_DATA_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1856 m_UrbStatusCode = USBD_STATUS_DATA_OVERRUN;
1857 break;
1858 case OHCI_TD_CONDITION_DATA_UNDERRUN:
1859 if (m_Irp)
1860 {
1861 //
1862 // get current irp stack location
1863 //
1864 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1865
1866 //
1867 // get urb
1868 //
1869 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1870
1871 if(Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
1872 {
1873 //
1874 // short packets are ok
1875 //
1876 ASSERT(Urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER);
1877 m_NtStatusCode = STATUS_SUCCESS;
1878 break;
1879 }
1880 }
1881 DPRINT1("OHCI_TD_CONDITION_DATA_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1882 m_UrbStatusCode = USBD_STATUS_DATA_UNDERRUN;
1883 break;
1884 case OHCI_TD_CONDITION_BUFFER_OVERRUN:
1885 DPRINT1("OHCI_TD_CONDITION_BUFFER_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1886 m_UrbStatusCode = USBD_STATUS_BUFFER_OVERRUN;
1887 break;
1888 case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
1889 DPRINT1("OHCI_TD_CONDITION_BUFFER_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
1890 m_UrbStatusCode = USBD_STATUS_BUFFER_UNDERRUN;
1891 break;
1892 }
1893 }
1894
1895 //
1896 // get next
1897 //
1898 TransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
1899 }
1900 }
1901 }
1902
1903 VOID
1904 STDMETHODCALLTYPE
1905 CUSBRequest::CompletionCallback()
1906 {
1907 PIO_STACK_LOCATION IoStack;
1908 PURB Urb;
1909
1910 DPRINT("CUSBRequest::CompletionCallback\n");
1911
1912 if (m_Irp)
1913 {
1914 //
1915 // set irp completion status
1916 //
1917 m_Irp->IoStatus.Status = m_NtStatusCode;
1918
1919 //
1920 // get current irp stack location
1921 //
1922 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1923
1924 //
1925 // get urb
1926 //
1927 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1928
1929 //
1930 // store urb status
1931 //
1932 Urb->UrbHeader.Status = m_UrbStatusCode;
1933
1934 //
1935 // Check if the MDL was created
1936 //
1937 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
1938 {
1939 //
1940 // Free Mdl
1941 //
1942 IoFreeMdl(m_TransferBufferMDL);
1943 }
1944
1945 //
1946 // FIXME calculate length
1947 //
1948
1949 //
1950 // complete request
1951 //
1952 IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
1953 }
1954 else
1955 {
1956 //
1957 // signal completion event
1958 //
1959 PC_ASSERT(m_CompletionEvent);
1960 KeSetEvent(m_CompletionEvent, 0, FALSE);
1961 }
1962 }
1963
1964 //-----------------------------------------------------------------------------------------
1965 NTSTATUS
1966 NTAPI
1967 InternalCreateUSBRequest(
1968 PUSBREQUEST *OutRequest)
1969 {
1970 PUSBREQUEST This;
1971
1972 //
1973 // allocate requests
1974 //
1975 This = new(NonPagedPool, TAG_USBOHCI) CUSBRequest(0);
1976 if (!This)
1977 {
1978 //
1979 // failed to allocate
1980 //
1981 return STATUS_INSUFFICIENT_RESOURCES;
1982 }
1983
1984 //
1985 // add reference count
1986 //
1987 This->AddRef();
1988
1989 //
1990 // return result
1991 //
1992 *OutRequest = (PUSBREQUEST)This;
1993
1994 //
1995 // done
1996 //
1997 return STATUS_SUCCESS;
1998 }