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 15 USBPORT_MakeSplitTransfer(IN PDEVICE_OBJECT FdoDevice, 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; 25 PUSBPORT_SCATTER_GATHER_ELEMENT Element0; 26 PUSBPORT_SCATTER_GATHER_ELEMENT Element1; 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 117 USBPORT_SplitBulkInterruptTransfer(IN PDEVICE_OBJECT FdoDevice, 118 IN PUSBPORT_ENDPOINT Endpoint, 119 IN PUSBPORT_TRANSFER Transfer, 120 IN PLIST_ENTRY List) 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, 192 USBPORT_TRANSFER, 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, 220 USBPORT_TRANSFER, 221 TransferLink); 222 RemoveHeadList(&tmplist); 223 224 ExFreePoolWithTag(SplitTransfer, USB_PORT_TAG); 225 } 226 227 return; 228 } 229 230 VOID 231 NTAPI 232 USBPORT_SplitTransfer(IN PDEVICE_OBJECT FdoDevice, 233 IN PUSBPORT_ENDPOINT Endpoint, 234 IN PUSBPORT_TRANSFER Transfer, 235 IN PLIST_ENTRY List) 236 { 237 ULONG TransferType; 238 239 DPRINT("USBPORT_SplitTransfer ... \n"); 240 241 InitializeListHead(List); 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 { 254 USBPORT_SplitBulkInterruptTransfer(FdoDevice, 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 278 USBPORT_DoneSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer) 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 314 USBPORT_CancelSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer) 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 } 337