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>
15 USBPORT_MakeSplitTransfer(IN PDEVICE_OBJECT FdoDevice
,
16 IN PUSBPORT_TRANSFER Transfer
,
17 IN PUSBPORT_TRANSFER SplitTransfer
,
18 IN ULONG MaxTransferSize
,
21 IN ULONG TransferRemainLen
,
22 IN ULONG TransferOffset
)
24 PUSBPORT_SCATTER_GATHER_LIST SplitSgList
;
25 PUSBPORT_SCATTER_GATHER_ELEMENT Element0
;
26 PUSBPORT_SCATTER_GATHER_ELEMENT Element1
;
30 DPRINT("USBPORT_MakeSplitTransfer: ... \n");
32 SplitSgList
= &SplitTransfer
->SgList
;
33 Element0
= &SplitSgList
->SgElement
[0];
35 SgLength
= Transfer
->SgList
.SgElement
[*SgIdx
].SgTransferLength
- *SgOffset
;
37 if (SgLength
> MaxTransferSize
)
39 /* SgLength > MaxTransferSize */
40 SplitTransfer
->SgList
.SgElementCount
= 1;
42 Element0
->SgOffset
= 0;
43 Element0
->SgTransferLength
= MaxTransferSize
;
44 Element0
->SgPhysicalAddress
.LowPart
= Transfer
->SgList
.SgElement
[*SgIdx
].SgPhysicalAddress
.LowPart
+ *SgOffset
;
46 SplitTransfer
->TransferParameters
.IsTransferSplited
= TRUE
;
47 SplitTransfer
->TransferParameters
.TransferBufferLength
= MaxTransferSize
;
49 SplitTransfer
->SgList
.CurrentVa
= Transfer
->SgList
.CurrentVa
+ TransferOffset
;
50 SplitTransfer
->SgList
.MappedSystemVa
= (PVOID
)((ULONG_PTR
)Transfer
->SgList
.MappedSystemVa
+ TransferOffset
);
52 SplitTransfer
->Flags
|= TRANSFER_FLAG_SPLITED
;
54 *SgOffset
+= MaxTransferSize
;
55 TransferRemainLen
-= MaxTransferSize
;
56 return TransferRemainLen
;
59 /* SgLength <= MaxTransferSize */
60 SplitTransfer
->SgList
.SgElementCount
= 1;
61 TransferRemainLen
-= SgLength
;
63 Element0
->SgOffset
= 0;
64 Element0
->SgTransferLength
= SgLength
;
65 Element0
->SgPhysicalAddress
.LowPart
= Transfer
->SgList
.SgElement
[*SgIdx
].SgPhysicalAddress
.LowPart
+ *SgOffset
;
67 SplitTransfer
->TransferParameters
.TransferBufferLength
= SgLength
;
68 SplitTransfer
->TransferParameters
.IsTransferSplited
= TRUE
;
70 SplitTransfer
->SgList
.CurrentVa
= Transfer
->SgList
.CurrentVa
+ TransferOffset
;
71 SplitTransfer
->SgList
.MappedSystemVa
= (PVOID
)((ULONG_PTR
)Transfer
->SgList
.MappedSystemVa
+ TransferOffset
);
73 SplitTransfer
->Flags
|= TRANSFER_FLAG_SPLITED
;
75 *SgOffset
+= SgLength
;
77 SgRemainLen
= MaxTransferSize
- SgLength
;
79 if (SgRemainLen
> TransferRemainLen
)
81 SgRemainLen
= TransferRemainLen
;
86 /* SgLength == MaxTransferSize */
89 return TransferRemainLen
;
92 /* SgLength < MaxTransferSize */
94 DPRINT1("MakeSplitTransfer: SgRemainLen - %x\n", SgRemainLen
);
95 DPRINT1("MakeSplitTransfer: SgIdx - %x\n", *SgIdx
);
99 SplitTransfer
->SgList
.SgElementCount
++;
101 Element1
= &SplitSgList
->SgElement
[1];
103 Element1
->SgOffset
= SgRemainLen
;
104 Element1
->SgTransferLength
= Element0
->SgTransferLength
;
105 Element1
->SgPhysicalAddress
.LowPart
= Transfer
->SgList
.SgElement
[*SgIdx
].SgPhysicalAddress
.LowPart
+ *SgOffset
;
107 SplitTransfer
->TransferParameters
.TransferBufferLength
+= SgRemainLen
;
109 *SgOffset
+= SgRemainLen
;
110 TransferRemainLen
-= SgRemainLen
;
112 return TransferRemainLen
;
117 USBPORT_SplitBulkInterruptTransfer(IN PDEVICE_OBJECT FdoDevice
,
118 IN PUSBPORT_ENDPOINT Endpoint
,
119 IN PUSBPORT_TRANSFER Transfer
,
122 PUSBPORT_TRANSFER SplitTransfer
;
125 SIZE_T TransferBufferLength
;
126 SIZE_T MaxTransferSize
;
127 SIZE_T TransferOffset
= 0;
133 DPRINT("USBPORT_SplitBulkInterruptTransfer: ... \n");
135 MaxTransferSize
= Endpoint
->EndpointProperties
.TotalMaxPacketSize
*
136 (Endpoint
->EndpointProperties
.MaxTransferSize
/
137 Endpoint
->EndpointProperties
.TotalMaxPacketSize
);
139 if (Endpoint
->EndpointProperties
.MaxTransferSize
> PAGE_SIZE
)
141 KeBugCheckEx(BUGCODE_USB_DRIVER
, 1, 0, 0, 0);
144 TransferBufferLength
= Transfer
->TransferParameters
.TransferBufferLength
;
145 Transfer
->Flags
|= TRANSFER_FLAG_PARENT
;
147 NeedSplits
= TransferBufferLength
/ MaxTransferSize
+ 1;
149 InitializeListHead(&tmplist
);
151 DPRINT("USBPORT_SplitBulkInterruptTransfer: TransferBufferLength - %x, NeedSplits - %x\n",
152 TransferBufferLength
, NeedSplits
);
156 DPRINT1("USBPORT_SplitBulkInterruptTransfer: DbgBreakPoint \n");
161 for (ix
= 0; ix
< NeedSplits
; ++ix
)
163 SplitTransfer
= ExAllocatePoolWithTag(NonPagedPool
,
164 Transfer
->FullTransferLength
,
169 DPRINT1("USBPORT_SplitBulkInterruptTransfer: DbgBreakPoint \n");
174 RtlCopyMemory(SplitTransfer
, Transfer
, Transfer
->FullTransferLength
);
176 SplitTransfer
->MiniportTransfer
= (PVOID
)((ULONG_PTR
)SplitTransfer
+
177 SplitTransfer
->PortTransferLength
);
179 InsertTailList(&tmplist
, &SplitTransfer
->TransferLink
);
182 if (Transfer
->TransferParameters
.TransferBufferLength
== 0)
187 RemainLength
= Transfer
->TransferParameters
.TransferBufferLength
;
191 SplitTransfer
= CONTAINING_RECORD(tmplist
.Flink
,
195 RemoveHeadList(&tmplist
);
197 RemainLength
= USBPORT_MakeSplitTransfer(FdoDevice
,
206 TransferOffset
+= SplitTransfer
->TransferParameters
.TransferBufferLength
;
208 InsertTailList(List
, &SplitTransfer
->TransferLink
);
209 InsertTailList(&Transfer
->SplitTransfersList
,&SplitTransfer
->SplitLink
);
211 while (RemainLength
!= 0);
215 while (!IsListEmpty(&tmplist
))
217 DPRINT("USBPORT_SplitBulkInterruptTransfer: ... \n");
219 SplitTransfer
= CONTAINING_RECORD(tmplist
.Flink
,
222 RemoveHeadList(&tmplist
);
224 ExFreePoolWithTag(SplitTransfer
, USB_PORT_TAG
);
232 USBPORT_SplitTransfer(IN PDEVICE_OBJECT FdoDevice
,
233 IN PUSBPORT_ENDPOINT Endpoint
,
234 IN PUSBPORT_TRANSFER Transfer
,
239 DPRINT("USBPORT_SplitTransfer ... \n");
241 InitializeListHead(List
);
242 InitializeListHead(&Transfer
->SplitTransfersList
);
244 Transfer
->USBDStatus
= USBD_STATUS_SUCCESS
;
246 if (Transfer
->TransferParameters
.TransferBufferLength
>
247 Endpoint
->EndpointProperties
.MaxTransferSize
)
249 TransferType
= Endpoint
->EndpointProperties
.TransferType
;
251 if (TransferType
== USBPORT_TRANSFER_TYPE_BULK
||
252 TransferType
== USBPORT_TRANSFER_TYPE_INTERRUPT
)
254 USBPORT_SplitBulkInterruptTransfer(FdoDevice
,
259 else if (TransferType
== USBPORT_TRANSFER_TYPE_ISOCHRONOUS
||
260 TransferType
== USBPORT_TRANSFER_TYPE_CONTROL
)
262 KeBugCheckEx(BUGCODE_USB_DRIVER
, 1, 0, 0, 0);
266 DPRINT1("USBPORT_SplitTransfer: Unknown TransferType - %x\n",
272 InsertTailList(List
, &Transfer
->TransferLink
);
278 USBPORT_DoneSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer
)
280 PUSBPORT_TRANSFER ParentTransfer
;
283 DPRINT("USBPORT_DoneSplitTransfer: ... \n");
285 ParentTransfer
= SplitTransfer
->ParentTransfer
;
286 ParentTransfer
->CompletedTransferLen
+= SplitTransfer
->CompletedTransferLen
;
288 if (SplitTransfer
->USBDStatus
!= USBD_STATUS_SUCCESS
)
290 DPRINT1("USBPORT_DoneSplitTransfer: SplitTransfer->USBDStatus - %X\n",
291 SplitTransfer
->USBDStatus
);
293 ParentTransfer
->USBDStatus
= SplitTransfer
->USBDStatus
;
296 KeAcquireSpinLock(&ParentTransfer
->TransferSpinLock
, &OldIrql
);
298 RemoveEntryList(&SplitTransfer
->SplitLink
);
299 ExFreePoolWithTag(SplitTransfer
, USB_PORT_TAG
);
301 if (IsListEmpty(&ParentTransfer
->SplitTransfersList
))
303 KeReleaseSpinLock(&ParentTransfer
->TransferSpinLock
, OldIrql
);
304 USBPORT_DoneTransfer(ParentTransfer
);
308 KeReleaseSpinLock(&ParentTransfer
->TransferSpinLock
, OldIrql
);
314 USBPORT_CancelSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer
)
316 PUSBPORT_TRANSFER ParentTransfer
;
317 PUSBPORT_ENDPOINT Endpoint
;
320 DPRINT("USBPORT_CancelSplitTransfer \n");
322 Endpoint
= SplitTransfer
->Endpoint
;
323 ParentTransfer
= SplitTransfer
->ParentTransfer
;
324 ParentTransfer
->CompletedTransferLen
+= SplitTransfer
->CompletedTransferLen
;
326 KeAcquireSpinLock(&ParentTransfer
->TransferSpinLock
, &OldIrql
);
327 RemoveEntryList(&SplitTransfer
->SplitLink
);
328 KeReleaseSpinLock(&ParentTransfer
->TransferSpinLock
, OldIrql
);
330 ExFreePool(SplitTransfer
);
332 if (IsListEmpty(&ParentTransfer
->SplitTransfersList
))
334 InsertTailList(&Endpoint
->CancelList
, &ParentTransfer
->TransferLink
);