1 //
2 //    Copyright (C) Microsoft.  All rights reserved.
3 //
4 #ifndef _FXUSBPIPE_H_
5 #define _FXUSBPIPE_H_
6 
7 #include "fxusbrequestcontext.hpp"
8 #include "fxusbinterface.hpp"
9 
10 //
11 // Technically, EHCI can support 4MB, but the usb driver stack doesn't
12 // allocate enough TDs for such a transfer, here I arbitrarily chose 2MB
13 //
14 enum FxUsbPipeMaxTransferSize {
15     FxUsbPipeHighSpeedMaxTransferSize = 2*1024*1024 ,
16     FxUsbPipeLowSpeedMaxTransferSize = 256 * 1024,
17     FxUsbPipeControlMaxTransferSize =  4*1024
18 };
19 
20 struct FxUsbPipeTransferContext : public FxUsbRequestContext {
21     FxUsbPipeTransferContext(
22         __in FX_URB_TYPE UrbType
23         );
24 
25     ~FxUsbPipeTransferContext(
26         VOID
27         );
28 
29     __checkReturn
30     NTSTATUS
31     AllocateUrb(
32         __in USBD_HANDLE USBDHandle
33         );
34 
35     virtual
36     VOID
37     Dispose(
38         VOID
39         );
40 
41     virtual
42     VOID
43     CopyParameters(
44         __in FxRequestBase* Request
45         );
46 
47     virtual
48     VOID
49     StoreAndReferenceMemory(
50         __in FxRequestBuffer* Buffer
51         );
52 
53     virtual
54     VOID
55     ReleaseAndRestore(
56         __in FxRequestBase* Request
57         );
58 
59     VOID
60     SetUrbInfo(
61         __in USBD_PIPE_HANDLE PipeHandle,
62         __in ULONG TransferFlags
63         );
64 
65     USBD_STATUS
66     GetUsbdStatus(
67         VOID
68         );
69 
70     ULONG
71     GetUrbTransferLength(
72         VOID
73         )
74     {
75 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
76         return m_Urb->TransferBufferLength;
77 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
78         return m_UmUrb.UmUrbBulkOrInterruptTransfer.TransferBufferLength;
79 #endif
80     }
81 
82 private:
83     USBD_HANDLE m_USBDHandle;
84 
85 public:
86     _URB_BULK_OR_INTERRUPT_TRANSFER m_UrbLegacy;
87 
88     //
89     // m_Urb will either point to m_UrbLegacy or one allocated by USBD_UrbAllocate
90     //
91     _URB_BULK_OR_INTERRUPT_TRANSFER* m_Urb;
92 
93     PMDL m_PartialMdl;
94 
95     BOOLEAN m_UnlockPages;
96 };
97 
98 struct FxUsbUrbContext : public FxUsbRequestContext {
99     FxUsbUrbContext(
100         VOID
101         );
102 
103     USBD_STATUS
104     GetUsbdStatus(
105         VOID
106         );
107 
108     virtual
109     VOID
110     StoreAndReferenceMemory(
111         __in FxRequestBuffer* Buffer
112         );
113 
114     virtual
115     VOID
116     ReleaseAndRestore(
117         __in FxRequestBase* Request
118         );
119 
120     PURB m_pUrb;
121 };
122 
123 struct FxUsbPipeRequestContext : public FxUsbRequestContext {
124     FxUsbPipeRequestContext(
125         __in FX_URB_TYPE FxUrbType
126         );
127 
128     ~FxUsbPipeRequestContext(
129         VOID
130         );
131 
132     __checkReturn
133     NTSTATUS
134     AllocateUrb(
135         __in USBD_HANDLE USBDHandle
136         );
137 
138     virtual
139     VOID
140     Dispose(
141         VOID
142         );
143 
144     VOID
145     SetInfo(
146         __in WDF_USB_REQUEST_TYPE Type,
147         __in USBD_PIPE_HANDLE PipeHandle,
148         __in USHORT Function
149         );
150 
151 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
152     VOID
153     SetInfo(
154         __in WDF_USB_REQUEST_TYPE Type,
155         __in WINUSB_INTERFACE_HANDLE WinUsbHandle,
156         __in UCHAR PipeId,
157         __in USHORT Function
158         );
159 #endif
160 
161     USBD_STATUS
162     GetUsbdStatus(
163         VOID
164         );
165 
166 private:
167     USBD_HANDLE m_USBDHandle;
168 
169 public:
170     _URB_PIPE_REQUEST m_UrbLegacy;
171 
172     //
173     // m_Urb will either point to m_UrbLegacy or one allocated by USBD_UrbAllocate
174     //
175     _URB_PIPE_REQUEST* m_Urb;
176 
177 };
178 
179 struct FxUsbPipeRepeatReader {
180     //
181     // Request used to send IRPs
182     //
183     FxRequest* Request;
184 
185     //
186     // IRP out of Request.  Store it off so we don't have to call
187     // Request->GetSubmitIrp() everytime.
188     //
189     MdIrp RequestIrp;
190 
191     //
192     // The containing parent
193     //
194     FxUsbPipeContinuousReader* Parent;
195 
196 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
197     //
198     // DPC to queue ourselves to when a read completes so that we don't spin in
199     // the same thread repeatedly.
200     //
201     KDPC Dpc;
202 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
203     //
204     // Workitem to queue ourselves to when a read completes so that we don't recurse in
205     // the same thread repeatedly.
206     //
207     MxWorkItem m_ReadWorkItem;
208 
209     //
210     // Check if the CR got called on a recursive call
211     //
212     LONG  ThreadOwnerId;
213 #endif
214 
215     //
216     // Event that is set when the reader has completed and is not
217     //
218     MxEvent ReadCompletedEvent;
219 };
220 
221 #define NUM_PENDING_READS_DEFAULT   (2)
222 #define NUM_PENDING_READS_MAX       (10)
223 
224 //
225 // Work-item callback flags
226 //
227 #define FX_USB_WORKITEM_IN_PROGRESS     (0x00000001)
228 #define FX_USB_WORKITEM_RERUN           (0x00000002)
229 
230 //
231 // In theory this can be a base class independent of bus type, but this is
232 // easier for now and there is no need on another bus type yet.
233 //
234 struct FxUsbPipeContinuousReader : public FxStump {
235 public:
236     FxUsbPipeContinuousReader(
237         __in FxUsbPipe* Pipe,
238         __in UCHAR NumReaders
239         );
240 
241     ~FxUsbPipeContinuousReader();
242 
243     _Must_inspect_result_
244     NTSTATUS
245     Config(
246         __in PWDF_USB_CONTINUOUS_READER_CONFIG Config,
247         __in size_t TotalBufferLength
248         );
249 
250     PVOID
251     operator new(
252         __in size_t Size,
253         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
254         __range(1, NUM_PENDING_READS_MAX) ULONG NumReaders
255         );
256 
257     _Must_inspect_result_
258     NTSTATUS
259     FormatRepeater(
260         __in FxUsbPipeRepeatReader* Repeater
261         );
262 
263     VOID
264     CancelRepeaters(
265         VOID
266         );
267 
268     ULONG
269     ResubmitRepeater(
270         __in FxUsbPipeRepeatReader* Repeater,
271         __out NTSTATUS* Status
272         );
273 
274 protected:
275     VOID
276     DeleteMemory(
277         __in FxRequestBase* Request
278         )
279     {
280         FxRequestContext* pContext;
281 
282         pContext = Request->GetContext();
283         if (pContext != NULL && pContext->m_RequestMemory != NULL) {
284             pContext->m_RequestMemory->Delete();
285             //
286             // NOTE: Don't NULL out the m_RequestMemory member as this will
287             // prevent Reuse from releasing a reference on the m_RequestMemory object
288             // and hence these memory objects will not be freed.
289             //
290         }
291     }
292 
293     BOOLEAN
294     QueueWorkItemLocked(
295         __in FxUsbPipeRepeatReader* Repeater
296         );
297 
298     __inline
299     VOID
300     FxUsbPipeRequestWorkItemHandler(
301         __in FxUsbPipeRepeatReader* FailedRepeater
302         );
303 
304     static
305     MdDeferredRoutineType
306     _FxUsbPipeContinuousReadDpc;
307 
308     static
309     MX_WORKITEM_ROUTINE
310     _ReadWorkItem;
311 
312 
313     static
314     EVT_WDF_REQUEST_COMPLETION_ROUTINE
315     _FxUsbPipeRequestComplete;
316 
317     static
318     EVT_SYSTEMWORKITEM
319     _FxUsbPipeRequestWorkItemThunk;
320 
321 public:
322     //
323     // Completion routine for the client
324     //
325     PFN_WDF_USB_READER_COMPLETION_ROUTINE m_ReadCompleteCallback;
326 
327     //
328     // Context for completion routine
329     //
330     WDFCONTEXT m_ReadCompleteContext;
331 
332     //
333     // Callback to invoke when a reader fails
334     //
335     PFN_WDF_USB_READERS_FAILED m_ReadersFailedCallback;
336 
337     //
338     // The owning pipe
339     //
340     FxUsbPipe* m_Pipe;
341 
342     //
343     // Lookaside list from which we will allocate buffers for each new read
344     //
345     FxLookasideList* m_Lookaside;
346 
347     //
348     // The devobj we are sending requests to
349     //
350     MdDeviceObject m_TargetDevice;
351 
352     //
353     // Offsets and length into the memory buffers created by the lookaside list
354     //
355     WDFMEMORY_OFFSET m_Offsets;
356 
357     //
358     // Work item to queue when we hit various errors
359     //
360     FxSystemWorkItem* m_WorkItem;
361 
362     //
363     // Work item re-run context.
364     //
365     PVOID m_WorkItemRerunContext;
366 
367     //
368     // This is a pointer to the work-item's thread object. This value is
369     // used for not deadlocking when misbehaved drivers (< v1.9) call
370     // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback.
371     //
372     volatile POINTER_ALIGNMENT MxThread m_WorkItemThread;
373 
374     //
375     // Work item flags (see FX_USB_WORKITEM_Xxx defines).
376     //
377     ULONG m_WorkItemFlags;
378 
379     //
380     // Number of readers who have failed due to internal allocation errors
381     //
382     UCHAR m_NumFailedReaders;
383 
384     //
385     // Number of readers
386     //
387     UCHAR m_NumReaders;
388 
389     //
390     // Value to use with InterlockedXxx to test to see if a work item has been
391     // queued or not
392     //
393     BOOLEAN m_WorkItemQueued;
394 
395     //
396     // Track whether the readers should be submitted when moving into the start
397     // state.  We cannot just track a start -> start transition and not send
398     // the readers on that particular state transition because the first time
399     // we need to send the readers, the target is already in the started state
400     //
401     BOOLEAN m_ReadersSubmitted;
402 
403     //
404     // Open ended array of readers.  MUST be the last element in this structure.
405     //
406     FxUsbPipeRepeatReader m_Readers[1];
407 };
408 
409 class FxUsbPipe : public FxIoTarget {
410 public:
411     friend FxUsbDevice;
412     friend FxUsbInterface;
413     friend FxUsbPipeContinuousReader;
414 
415     FxUsbPipe(
416         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
417         __in FxUsbDevice* UsbDevice
418         );
419 
420     VOID
421     InitPipe(
422         __in PUSBD_PIPE_INFORMATION PipeInfo,
423         __in UCHAR InterfaceNumber,
424         __in FxUsbInterface* UsbInterface
425         );
426 
427 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
428     VOID
429     InitPipe(
430         __in PWINUSB_PIPE_INFORMATION PipeInfo,
431         __in UCHAR InterfaceNumber,
432         __in FxUsbInterface* UsbInterface
433         );
434 #endif
435 
436     _Must_inspect_result_
437     virtual
438     NTSTATUS
439     GotoStartState(
440         __in PLIST_ENTRY    RequestListHead,
441         __in BOOLEAN        Lock = TRUE
442         );
443 
444     virtual
445     VOID
446     GotoStopState(
447         __in WDF_IO_TARGET_SENT_IO_ACTION   Action,
448         __in PSINGLE_LIST_ENTRY             SentRequestListHead,
449         __out PBOOLEAN                      Wait,
450         __in BOOLEAN                        LockSelf
451         );
452 
453     VOID
454     GotoPurgeState(
455         __in WDF_IO_TARGET_PURGE_IO_ACTION  Action,
456         __in PLIST_ENTRY                    PendedRequestListHead,
457         __in PSINGLE_LIST_ENTRY             SentRequestListHead,
458         __out PBOOLEAN                      Wait,
459         __in BOOLEAN                        LockSelf
460         );
461 
462     virtual
463     VOID
464     GotoRemoveState(
465         __in WDF_IO_TARGET_STATE    NewState,
466         __in PLIST_ENTRY            PendedRequestListHead,
467         __in PSINGLE_LIST_ENTRY     SentRequestListHead,
468         __in BOOLEAN                Lock,
469         __out PBOOLEAN              Wait
470         );
471 
472     virtual
473     VOID
474     WaitForSentIoToComplete(
475         VOID
476         );
477 
478     __inline
479     VOID
480     SetNoCheckPacketSize(
481         VOID
482         )
483     {
484         m_CheckPacketSize = FALSE;
485     }
486 
487     VOID
488     GetInformation(
489         __out PWDF_USB_PIPE_INFORMATION PipeInformation
490         );
491 
492     BOOLEAN
493     IsType(
494         __in WDF_USB_PIPE_TYPE Type
495         );
496 
497 
498     WDF_USB_PIPE_TYPE
499     GetType(
500         VOID
501         );
502 
503     WDFUSBPIPE
504     GetHandle(
505         VOID
506         )
507     {
508         return (WDFUSBPIPE) GetObjectHandle();
509     }
510 
511     __inline
512     BOOLEAN
513     IsInEndpoint(
514         VOID
515         )
516     {
517         //
518         // USB_ENDPOINT_DIRECTION_IN just does a bitwise compre so it could
519         // return 0 or some non zero value.  Make sure the non zero value is
520         // TRUE
521         //
522 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
523         return USB_ENDPOINT_DIRECTION_IN(m_PipeInformation.EndpointAddress) ? TRUE : FALSE;
524 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
525         return USB_ENDPOINT_DIRECTION_IN(m_PipeInformationUm.PipeId) ? TRUE : FALSE;
526 #endif
527     }
528 
529     __inline
530     BOOLEAN
531     IsOutEndpoint(
532         VOID
533         )
534     {
535         //
536         // USB_ENDPOINT_DIRECTION_OUT just does a bitwise compre so it could
537         // return 0 or some non zero value.  Make sure the non zero value is
538         // TRUE
539         //
540 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
541         return USB_ENDPOINT_DIRECTION_OUT(m_PipeInformation.EndpointAddress) ? TRUE : FALSE;
542 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
543         return USB_ENDPOINT_DIRECTION_OUT(m_PipeInformationUm.PipeId) ? TRUE : FALSE;
544 #endif
545     }
546 
547     _Must_inspect_result_
548     NTSTATUS
549     InitContinuousReader(
550         __in PWDF_USB_CONTINUOUS_READER_CONFIG Config,
551         __in size_t TotalBufferLength
552         );
553 
554     ULONG
555     GetMaxPacketSize(
556         VOID
557         )
558     {
559 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
560         return  m_PipeInformation.MaximumPacketSize;
561 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
562         return  m_PipeInformationUm.MaximumPacketSize;
563 #endif
564     }
565 
566     _Must_inspect_result_
567     NTSTATUS
568     ValidateTransferLength(
569         __in size_t Length
570         )
571     {
572         //
573         // Assumes this is not a control pipe
574         //
575         if (m_CheckPacketSize &&
576 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
577             (Length % m_PipeInformation.MaximumPacketSize) != 0) {
578 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
579             (Length % m_PipeInformationUm.MaximumPacketSize) != 0) {
580 #endif
581             return STATUS_INVALID_BUFFER_SIZE;
582         }
583         else {
584             return STATUS_SUCCESS;
585         }
586     }
587 
588     _Must_inspect_result_
589     NTSTATUS
590     FormatTransferRequest(
591         __in FxRequestBase* Request,
592         __in FxRequestBuffer* Buffer,
593         __in ULONG TransferFlags = 0
594         );
595 
596     _Must_inspect_result_
597     NTSTATUS
598     FormatAbortRequest(
599         __in FxRequestBase* Request
600         );
601 
602     _Must_inspect_result_
603     NTSTATUS
604     FormatResetRequest(
605         __in FxRequestBase* Request
606         );
607 
608     static
609     _Must_inspect_result_
610     NTSTATUS
611     _FormatTransfer(
612         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
613         __in WDFUSBPIPE Pipe,
614         __in WDFREQUEST Request,
615         __in_opt WDFMEMORY TransferMemory,
616         __in_opt PWDFMEMORY_OFFSET TransferOffsets,
617         __in ULONG Flags
618         );
619 
620     static
621     _Must_inspect_result_
622     NTSTATUS
623     _SendTransfer(
624         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
625         __in WDFUSBPIPE Pipe,
626         __in_opt WDFREQUEST Request,
627         __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions,
628         __in_opt PWDF_MEMORY_DESCRIPTOR MemoryDescriptor,
629         __out_opt PULONG BytesTransferred,
630         __in ULONG Flags
631         );
632 
633     USBD_PIPE_HANDLE
634     WdmGetPipeHandle(
635         VOID
636         )
637     {
638         return m_PipeInformation.PipeHandle;
639     }
640 
641     static
642     WDF_USB_PIPE_TYPE
643     _UsbdPipeTypeToWdf(
644          __in USBD_PIPE_TYPE UsbdPipeType
645          )
646     {
647         const static WDF_USB_PIPE_TYPE types[] = {
648             WdfUsbPipeTypeControl,              // UsbdPipeTypeControl
649             WdfUsbPipeTypeIsochronous,          // UsbdPipeTypeIsochronous
650             WdfUsbPipeTypeBulk,                 // UsbdPipeTypeBulk
651             WdfUsbPipeTypeInterrupt,            // UsbdPipeTypeInterrupt
652         };
653 
654         if (UsbdPipeType < sizeof(types)/sizeof(types[0])) {
655             return types[UsbdPipeType];
656         }
657         else {
658             return WdfUsbPipeTypeInvalid;
659         }
660     }
661 
662     NTSTATUS
663     Reset(
664         VOID
665         );
666 
667     USBD_HANDLE
668     GetUSBDHandle(
669         VOID
670         )
671     {
672         return m_USBDHandle;
673     }
674 
675     FX_URB_TYPE
676     GetUrbType(
677         VOID
678         )
679     {
680         return m_UrbType;
681     }
682 
683 public:
684     //
685     // Link for FxUsbDevice to use to hold a list of Pipes
686     //
687     LIST_ENTRY m_ListEntry;
688 
689 protected:
690     ~FxUsbPipe();
691 
692     virtual
693     BOOLEAN
694     Dispose(
695         VOID
696         );
697 
698     FxUsbDevice* m_UsbDevice;
699 
700     FxUsbInterface* m_UsbInterface;
701 
702     //
703     // If the pipe does not have a continuous reader, this field is NULL.
704     // It is also cleared within the pipe's Dispose function after deleting
705     // the continuous reader to prevent misbehaved drivers from
706     // crashing the system when they call WdfIoTargetStop from their usb pipe's
707     // destroy callback.
708     //
709     FxUsbPipeContinuousReader* m_Reader;
710 
711     //
712     // Information about this pipe
713     //
714     USBD_PIPE_INFORMATION  m_PipeInformation;
715 
716 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
717 
718 
719 
720     WINUSB_PIPE_INFORMATION m_PipeInformationUm;
721 #endif
722 
723     //
724     // Interface associated with this pipe
725     //
726     UCHAR m_InterfaceNumber;
727 
728     //
729     // Indicates if we should check that the buffer being trasnfered is of a
730     // multiple of max packet size.
731     //
732     BOOLEAN m_CheckPacketSize;
733 
734     //
735     // The USBD_HANDLE exchanged by FxUsbDevice
736     //
737     USBD_HANDLE m_USBDHandle;
738 
739     //
740     // If the client driver submits an URB to do a USB transfer, this field indicates
741     // the type of that Urb
742     //
743     FX_URB_TYPE m_UrbType;
744 
745 };
746 
747 #endif // _FXUSBPIPE_H_
748