ReactOS  0.4.14-dev-77-gd9e7c48
trfsplit.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS USB Port Driver
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: USBPort split transfer functions
5  * COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbport.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 ULONG
14 NTAPI
16  IN PUSBPORT_TRANSFER Transfer,
17  IN PUSBPORT_TRANSFER SplitTransfer,
18  IN ULONG MaxTransferSize,
19  IN PULONG SgIdx,
20  IN PULONG SgOffset,
21  IN ULONG TransferRemainLen,
22  IN ULONG TransferOffset)
23 {
24  PUSBPORT_SCATTER_GATHER_LIST SplitSgList;
27  SIZE_T SgLength;
28  SIZE_T SgRemainLen;
29 
30  DPRINT("USBPORT_MakeSplitTransfer: ... \n");
31 
32  SplitSgList = &SplitTransfer->SgList;
33  Element0 = &SplitSgList->SgElement[0];
34 
35  SgLength = Transfer->SgList.SgElement[*SgIdx].SgTransferLength - *SgOffset;
36 
37  if (SgLength > MaxTransferSize)
38  {
39  /* SgLength > MaxTransferSize */
40  SplitTransfer->SgList.SgElementCount = 1;
41 
42  Element0->SgOffset = 0;
43  Element0->SgTransferLength = MaxTransferSize;
44  Element0->SgPhysicalAddress.LowPart = Transfer->SgList.SgElement[*SgIdx].SgPhysicalAddress.LowPart + *SgOffset;
45 
46  SplitTransfer->TransferParameters.IsTransferSplited = TRUE;
47  SplitTransfer->TransferParameters.TransferBufferLength = MaxTransferSize;
48 
49  SplitTransfer->SgList.CurrentVa = Transfer->SgList.CurrentVa + TransferOffset;
50  SplitTransfer->SgList.MappedSystemVa = (PVOID)((ULONG_PTR)Transfer->SgList.MappedSystemVa + TransferOffset);
51 
52  SplitTransfer->Flags |= TRANSFER_FLAG_SPLITED;
53 
54  *SgOffset += MaxTransferSize;
55  TransferRemainLen -= MaxTransferSize;
56  return TransferRemainLen;
57  }
58 
59  /* SgLength <= MaxTransferSize */
60  SplitTransfer->SgList.SgElementCount = 1;
61  TransferRemainLen -= SgLength;
62 
63  Element0->SgOffset = 0;
64  Element0->SgTransferLength = SgLength;
65  Element0->SgPhysicalAddress.LowPart = Transfer->SgList.SgElement[*SgIdx].SgPhysicalAddress.LowPart + *SgOffset;
66 
67  SplitTransfer->TransferParameters.TransferBufferLength = SgLength;
68  SplitTransfer->TransferParameters.IsTransferSplited = TRUE;
69 
70  SplitTransfer->SgList.CurrentVa = Transfer->SgList.CurrentVa + TransferOffset;
71  SplitTransfer->SgList.MappedSystemVa = (PVOID)((ULONG_PTR)Transfer->SgList.MappedSystemVa + TransferOffset);
72 
73  SplitTransfer->Flags |= TRANSFER_FLAG_SPLITED;
74 
75  *SgOffset += SgLength;
76 
77  SgRemainLen = MaxTransferSize - SgLength;
78 
79  if (SgRemainLen > TransferRemainLen)
80  {
81  SgRemainLen = TransferRemainLen;
82  }
83 
84  if (!SgRemainLen)
85  {
86  /* SgLength == MaxTransferSize */
87  ++*SgIdx;
88  *SgOffset = 0;
89  return TransferRemainLen;
90  }
91 
92  /* SgLength < MaxTransferSize */
93 
94  DPRINT1("MakeSplitTransfer: SgRemainLen - %x\n", SgRemainLen);
95  DPRINT1("MakeSplitTransfer: SgIdx - %x\n", *SgIdx);
96  ++*SgIdx;
97 
98  *SgOffset = 0;
99  SplitTransfer->SgList.SgElementCount++;
100 
101  Element1 = &SplitSgList->SgElement[1];
102 
103  Element1->SgOffset = SgRemainLen;
104  Element1->SgTransferLength = Element0->SgTransferLength;
105  Element1->SgPhysicalAddress.LowPart = Transfer->SgList.SgElement[*SgIdx].SgPhysicalAddress.LowPart + *SgOffset;
106 
107  SplitTransfer->TransferParameters.TransferBufferLength += SgRemainLen;
108 
109  *SgOffset += SgRemainLen;
110  TransferRemainLen -= SgRemainLen;
111 
112  return TransferRemainLen;
113 }
114 
115 VOID
116 NTAPI
118  IN PUSBPORT_ENDPOINT Endpoint,
119  IN PUSBPORT_TRANSFER Transfer,
121 {
122  PUSBPORT_TRANSFER SplitTransfer;
123  LIST_ENTRY tmplist;
124  ULONG NeedSplits;
125  SIZE_T TransferBufferLength;
126  SIZE_T MaxTransferSize;
127  SIZE_T TransferOffset = 0;
128  SIZE_T RemainLength;
129  ULONG ix;
130  ULONG SgIdx = 0;
131  ULONG SgOffset = 0;
132 
133  DPRINT("USBPORT_SplitBulkInterruptTransfer: ... \n");
134 
135  MaxTransferSize = Endpoint->EndpointProperties.TotalMaxPacketSize *
136  (Endpoint->EndpointProperties.MaxTransferSize /
137  Endpoint->EndpointProperties.TotalMaxPacketSize);
138 
139  if (Endpoint->EndpointProperties.MaxTransferSize > PAGE_SIZE)
140  {
141  KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0);
142  }
143 
144  TransferBufferLength = Transfer->TransferParameters.TransferBufferLength;
145  Transfer->Flags |= TRANSFER_FLAG_PARENT;
146 
147  NeedSplits = TransferBufferLength / MaxTransferSize + 1;
148 
149  InitializeListHead(&tmplist);
150 
151  DPRINT("USBPORT_SplitBulkInterruptTransfer: TransferBufferLength - %x, NeedSplits - %x\n",
152  TransferBufferLength, NeedSplits);
153 
154  if (!NeedSplits)
155  {
156  DPRINT1("USBPORT_SplitBulkInterruptTransfer: DbgBreakPoint \n");
157  DbgBreakPoint();
158  goto Exit;
159  }
160 
161  for (ix = 0; ix < NeedSplits; ++ix)
162  {
163  SplitTransfer = ExAllocatePoolWithTag(NonPagedPool,
164  Transfer->FullTransferLength,
165  USB_PORT_TAG);
166 
167  if (!SplitTransfer)
168  {
169  DPRINT1("USBPORT_SplitBulkInterruptTransfer: DbgBreakPoint \n");
170  DbgBreakPoint();
171  goto Exit;
172  }
173 
174  RtlCopyMemory(SplitTransfer, Transfer, Transfer->FullTransferLength);
175 
176  SplitTransfer->MiniportTransfer = (PVOID)((ULONG_PTR)SplitTransfer +
177  SplitTransfer->PortTransferLength);
178 
179  InsertTailList(&tmplist, &SplitTransfer->TransferLink);
180  }
181 
182  if (Transfer->TransferParameters.TransferBufferLength == 0)
183  {
184  goto Exit;
185  }
186 
187  RemainLength = Transfer->TransferParameters.TransferBufferLength;
188 
189  do
190  {
191  SplitTransfer = CONTAINING_RECORD(tmplist.Flink,
193  TransferLink);
194 
195  RemoveHeadList(&tmplist);
196 
197  RemainLength = USBPORT_MakeSplitTransfer(FdoDevice,
198  Transfer,
199  SplitTransfer,
200  MaxTransferSize,
201  &SgIdx,
202  &SgOffset,
203  RemainLength,
204  TransferOffset);
205 
206  TransferOffset += SplitTransfer->TransferParameters.TransferBufferLength;
207 
208  InsertTailList(List, &SplitTransfer->TransferLink);
209  InsertTailList(&Transfer->SplitTransfersList,&SplitTransfer->SplitLink);
210  }
211  while (RemainLength != 0);
212 
213 Exit:
214 
215  while (!IsListEmpty(&tmplist))
216  {
217  DPRINT("USBPORT_SplitBulkInterruptTransfer: ... \n");
218 
219  SplitTransfer = CONTAINING_RECORD(tmplist.Flink,
221  TransferLink);
222  RemoveHeadList(&tmplist);
223 
224  ExFreePoolWithTag(SplitTransfer, USB_PORT_TAG);
225  }
226 
227  return;
228 }
229 
230 VOID
231 NTAPI
233  IN PUSBPORT_ENDPOINT Endpoint,
234  IN PUSBPORT_TRANSFER Transfer,
236 {
237  ULONG TransferType;
238 
239  DPRINT("USBPORT_SplitTransfer ... \n");
240 
242  InitializeListHead(&Transfer->SplitTransfersList);
243 
244  Transfer->USBDStatus = USBD_STATUS_SUCCESS;
245 
246  if (Transfer->TransferParameters.TransferBufferLength >
247  Endpoint->EndpointProperties.MaxTransferSize)
248  {
249  TransferType = Endpoint->EndpointProperties.TransferType;
250 
251  if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
252  TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
253  {
255  Endpoint,
256  Transfer,
257  List);
258  }
259  else if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS ||
260  TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
261  {
262  KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0);
263  }
264  else
265  {
266  DPRINT1("USBPORT_SplitTransfer: Unknown TransferType - %x\n",
267  TransferType);
268  }
269  }
270  else
271  {
272  InsertTailList(List, &Transfer->TransferLink);
273  }
274 }
275 
276 VOID
277 NTAPI
279 {
280  PUSBPORT_TRANSFER ParentTransfer;
281  KIRQL OldIrql;
282 
283  DPRINT("USBPORT_DoneSplitTransfer: ... \n");
284 
285  ParentTransfer = SplitTransfer->ParentTransfer;
286  ParentTransfer->CompletedTransferLen += SplitTransfer->CompletedTransferLen;
287 
288  if (SplitTransfer->USBDStatus != USBD_STATUS_SUCCESS)
289  {
290  DPRINT1("USBPORT_DoneSplitTransfer: SplitTransfer->USBDStatus - %X\n",
291  SplitTransfer->USBDStatus);
292 
293  ParentTransfer->USBDStatus = SplitTransfer->USBDStatus;
294  }
295 
296  KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql);
297 
298  RemoveEntryList(&SplitTransfer->SplitLink);
299  ExFreePoolWithTag(SplitTransfer, USB_PORT_TAG);
300 
301  if (IsListEmpty(&ParentTransfer->SplitTransfersList))
302  {
303  KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
304  USBPORT_DoneTransfer(ParentTransfer);
305  }
306  else
307  {
308  KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
309  }
310 }
311 
312 VOID
313 NTAPI
315 {
316  PUSBPORT_TRANSFER ParentTransfer;
317  PUSBPORT_ENDPOINT Endpoint;
318  KIRQL OldIrql;
319 
320  DPRINT("USBPORT_CancelSplitTransfer \n");
321 
322  Endpoint = SplitTransfer->Endpoint;
323  ParentTransfer = SplitTransfer->ParentTransfer;
324  ParentTransfer->CompletedTransferLen += SplitTransfer->CompletedTransferLen;
325 
326  KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql);
327  RemoveEntryList(&SplitTransfer->SplitLink);
328  KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
329 
330  ExFreePool(SplitTransfer);
331 
332  if (IsListEmpty(&ParentTransfer->SplitTransfersList))
333  {
334  InsertTailList(&Endpoint->CancelList, &ParentTransfer->TransferLink);
335  }
336 }
LIST_ENTRY SplitLink
Definition: usbport.h:266
#define USBPORT_TRANSFER_TYPE_BULK
Definition: usbmport.h:9
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
USBPORT_TRANSFER_PARAMETERS TransferParameters
Definition: usbport.h:253
PHYSICAL_ADDRESS SgPhysicalAddress
Definition: usbmport.h:107
#define TRANSFER_FLAG_PARENT
Definition: usbport.h:138
#define USBPORT_TRANSFER_TYPE_CONTROL
Definition: usbmport.h:8
#define InsertTailList(ListHead, Entry)
void DbgBreakPoint()
Definition: mach.c:553
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
uint32_t ULONG_PTR
Definition: typedefs.h:63
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
#define USB_PORT_TAG
Definition: usbport.h:44
UCHAR KIRQL
Definition: env_spec_w32.h:591
struct _USBPORT_TRANSFER * ParentTransfer
Definition: usbport.h:263
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
void DPRINT(...)
Definition: polytest.cpp:61
void * PVOID
Definition: retypes.h:9
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
SIZE_T PortTransferLength
Definition: usbport.h:250
LIST_ENTRY TransferLink
Definition: usbport.h:256
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
VOID NTAPI USBPORT_SplitBulkInterruptTransfer(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_ENDPOINT Endpoint, IN PUSBPORT_TRANSFER Transfer, IN PLIST_ENTRY List)
Definition: trfsplit.c:117
LIST_ENTRY List
Definition: psmgr.c:57
static void Exit(void)
Definition: sock.c:1331
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
PVOID MiniportTransfer
Definition: usbport.h:249
VOID NTAPI USBPORT_SplitTransfer(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_ENDPOINT Endpoint, IN PUSBPORT_TRANSFER Transfer, IN PLIST_ENTRY List)
Definition: trfsplit.c:232
VOID NTAPI USBPORT_DoneTransfer(IN PUSBPORT_TRANSFER Transfer)
Definition: usbport.c:724
ULONG NTAPI USBPORT_MakeSplitTransfer(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_TRANSFER Transfer, IN PUSBPORT_TRANSFER SplitTransfer, IN ULONG MaxTransferSize, IN PULONG SgIdx, IN PULONG SgOffset, IN ULONG TransferRemainLen, IN ULONG TransferOffset)
Definition: trfsplit.c:15
VOID NTAPI USBPORT_DoneSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer)
Definition: trfsplit.c:278
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define USBD_STATUS_SUCCESS
Definition: usb.h:170
#define USBPORT_TRANSFER_TYPE_INTERRUPT
Definition: usbmport.h:10
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
ULONG LowPart
Definition: typedefs.h:104
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Definition: typedefs.h:117
#define USBPORT_TRANSFER_TYPE_ISOCHRONOUS
Definition: usbmport.h:7
SIZE_T FullTransferLength
Definition: usbport.h:251
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define TRANSFER_FLAG_SPLITED
Definition: usbport.h:136
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
unsigned int * PULONG
Definition: retypes.h:1
USBPORT_SCATTER_GATHER_ELEMENT SgElement[2]
Definition: usbmport.h:121
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
LIST_ENTRY SplitTransfersList
Definition: usbport.h:265
#define DPRINT1
Definition: precomp.h:8
VOID NTAPI USBPORT_CancelSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer)
Definition: trfsplit.c:314
unsigned int ULONG
Definition: retypes.h:1
KSPIN_LOCK TransferSpinLock
Definition: usbport.h:264
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
USBD_STATUS USBDStatus
Definition: usbport.h:257
ULONG CompletedTransferLen
Definition: usbport.h:258
LIST_ENTRY CancelList
Definition: usbport.h:228
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:107
#define ExFreePool(addr)
Definition: env_spec_w32.h:352