1 // Copyright (c) 2004, Antony C. Roberts 2 3 // Use of this file is subject to the terms 4 // described in the LICENSE.TXT file that 5 // accompanies this file. 6 // 7 // Your use of this file indicates your 8 // acceptance of the terms described in 9 // LICENSE.TXT. 10 // 11 // http://www.freebt.net 12 13 #include "fbtusb.h" 14 #include "fbtpnp.h" 15 #include "fbtpwr.h" 16 #include "fbtdev.h" 17 #include "fbtrwr.h" 18 #include "fbtwmi.h" 19 20 #include "fbtusr.h" 21 22 // Read/Write handler 23 NTSTATUS NTAPI FreeBT_DispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 24 { 25 PMDL mdl; 26 PURB urb; 27 ULONG totalLength; 28 ULONG stageLength; 29 NTSTATUS ntStatus; 30 ULONG_PTR virtualAddress; 31 PFILE_OBJECT fileObject; 32 PDEVICE_EXTENSION deviceExtension; 33 PIO_STACK_LOCATION irpStack; 34 PIO_STACK_LOCATION nextStack; 35 PFREEBT_RW_CONTEXT rwContext; 36 //ULONG maxLength=0; 37 38 urb = NULL; 39 mdl = NULL; 40 rwContext = NULL; 41 totalLength = 0; 42 irpStack = IoGetCurrentIrpStackLocation(Irp); 43 fileObject = irpStack->FileObject; 44 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 45 46 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Entered\n")); 47 48 if (deviceExtension->DeviceState != Working) 49 { 50 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Invalid device state\n")); 51 ntStatus = STATUS_INVALID_DEVICE_STATE; 52 goto FreeBT_DispatchRead_Exit; 53 54 } 55 56 // Make sure that any selective suspend request has been completed. 57 if (deviceExtension->SSEnable) 58 { 59 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Waiting on the IdleReqPendEvent\n")); 60 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, 61 Executive, 62 KernelMode, 63 FALSE, 64 NULL); 65 66 } 67 68 rwContext = (PFREEBT_RW_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(FREEBT_RW_CONTEXT)); 69 if (rwContext == NULL) 70 { 71 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for rwContext\n")); 72 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 73 goto FreeBT_DispatchRead_Exit; 74 75 } 76 77 if (Irp->MdlAddress) 78 { 79 totalLength = MmGetMdlByteCount(Irp->MdlAddress); 80 81 } 82 83 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Transfer data length = %d\n", totalLength)); 84 if (totalLength == 0) 85 { 86 ntStatus = STATUS_SUCCESS; 87 ExFreePool(rwContext); 88 goto FreeBT_DispatchRead_Exit; 89 90 } 91 92 virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress); 93 if (totalLength > deviceExtension->DataInPipe.MaximumPacketSize) 94 { 95 stageLength = deviceExtension->DataInPipe.MaximumPacketSize; 96 97 } 98 99 else 100 { 101 stageLength = totalLength; 102 103 } 104 105 mdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); 106 if (mdl == NULL) 107 { 108 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for mdl\n")); 109 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 110 ExFreePool(rwContext); 111 goto FreeBT_DispatchRead_Exit; 112 113 } 114 115 // map the portion of user-buffer described by an mdl to another mdl 116 IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) virtualAddress, stageLength); 117 urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER)); 118 if (urb == NULL) 119 { 120 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for urb\n")); 121 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 122 ExFreePool(rwContext); 123 IoFreeMdl(mdl); 124 goto FreeBT_DispatchRead_Exit; 125 126 } 127 128 UsbBuildInterruptOrBulkTransferRequest( 129 urb, 130 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 131 deviceExtension->DataInPipe.PipeHandle, 132 NULL, 133 mdl, 134 stageLength, 135 USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN, 136 NULL); 137 138 // set FREEBT_RW_CONTEXT parameters. 139 rwContext->Urb = urb; 140 rwContext->Mdl = mdl; 141 rwContext->Length = totalLength - stageLength; 142 rwContext->Numxfer = 0; 143 rwContext->VirtualAddress = virtualAddress + stageLength; 144 145 // use the original read/write irp as an internal device control irp 146 nextStack = IoGetNextIrpStackLocation(Irp); 147 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 148 nextStack->Parameters.Others.Argument1 = (PVOID) urb; 149 nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 150 IoSetCompletionRoutine(Irp, 151 (PIO_COMPLETION_ROUTINE)FreeBT_ReadCompletion, 152 rwContext, 153 TRUE, 154 TRUE, 155 TRUE); 156 157 // We return STATUS_PENDING; call IoMarkIrpPending. 158 IoMarkIrpPending(Irp); 159 160 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); 161 if (!NT_SUCCESS(ntStatus)) 162 { 163 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: IoCallDriver fails with status %X\n", ntStatus)); 164 165 // if the device was yanked out, then the pipeInformation 166 // field is invalid. 167 // similarly if the request was cancelled, then we need not 168 // invoked reset pipe/device. 169 if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) 170 { 171 ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->DataInPipe.PipeHandle); 172 if(!NT_SUCCESS(ntStatus)) 173 { 174 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: FreeBT_ResetPipe failed\n")); 175 ntStatus = FreeBT_ResetDevice(DeviceObject); 176 177 } 178 179 } 180 181 else 182 { 183 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n")); 184 185 } 186 187 } 188 189 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead::")); 190 FreeBT_IoIncrement(deviceExtension); 191 192 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: URB sent to lower driver, IRP is pending\n")); 193 194 // we return STATUS_PENDING and not the status returned by the lower layer. 195 return STATUS_PENDING; 196 197 FreeBT_DispatchRead_Exit: 198 Irp->IoStatus.Status = ntStatus; 199 Irp->IoStatus.Information = 0; 200 IoCompleteRequest(Irp, IO_NO_INCREMENT); 201 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Leaving\n")); 202 203 return ntStatus; 204 205 } 206 207 NTSTATUS NTAPI FreeBT_ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) 208 { 209 //ULONG stageLength; 210 NTSTATUS ntStatus; 211 //PIO_STACK_LOCATION nextStack; 212 PFREEBT_RW_CONTEXT rwContext; 213 PDEVICE_EXTENSION deviceExtension; 214 215 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 216 rwContext = (PFREEBT_RW_CONTEXT) Context; 217 ntStatus = Irp->IoStatus.Status; 218 219 UNREFERENCED_PARAMETER(DeviceObject); 220 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Entered\n")); 221 222 if (NT_SUCCESS(ntStatus)) 223 { 224 Irp->IoStatus.Information = rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; 225 226 } 227 228 else 229 { 230 Irp->IoStatus.Information = 0; 231 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ReadCompletion: - failed with status = %X\n", ntStatus)); 232 233 } 234 235 if (rwContext) 236 { 237 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: ::")); 238 FreeBT_IoDecrement(deviceExtension); 239 240 ExFreePool(rwContext->Urb); 241 IoFreeMdl(rwContext->Mdl); 242 ExFreePool(rwContext); 243 244 } 245 246 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Leaving\n")); 247 248 return ntStatus; 249 250 } 251 252 // Read/Write handler 253 NTSTATUS NTAPI FreeBT_DispatchWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 254 { 255 PMDL mdl; 256 PURB urb; 257 ULONG totalLength; 258 ULONG stageLength; 259 NTSTATUS ntStatus; 260 ULONG_PTR virtualAddress; 261 PFILE_OBJECT fileObject; 262 PDEVICE_EXTENSION deviceExtension; 263 PIO_STACK_LOCATION irpStack; 264 PIO_STACK_LOCATION nextStack; 265 PFREEBT_RW_CONTEXT rwContext; 266 //ULONG maxLength=0; 267 268 urb = NULL; 269 mdl = NULL; 270 rwContext = NULL; 271 totalLength = 0; 272 irpStack = IoGetCurrentIrpStackLocation(Irp); 273 fileObject = irpStack->FileObject; 274 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 275 276 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Entered\n")); 277 278 if (deviceExtension->DeviceState != Working) 279 { 280 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Invalid device state\n")); 281 ntStatus = STATUS_INVALID_DEVICE_STATE; 282 goto FreeBT_DispatchWrite_Exit; 283 284 } 285 286 // Make sure that any selective suspend request has been completed. 287 if (deviceExtension->SSEnable) 288 { 289 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteDispatch: Waiting on the IdleReqPendEvent\n")); 290 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, 291 Executive, 292 KernelMode, 293 FALSE, 294 NULL); 295 296 } 297 298 rwContext = (PFREEBT_RW_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(FREEBT_RW_CONTEXT)); 299 if (rwContext == NULL) 300 { 301 FreeBT_DbgPrint(1, ("FBTUSB: Failed to alloc mem for rwContext\n")); 302 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 303 goto FreeBT_DispatchWrite_Exit; 304 305 } 306 307 if (Irp->MdlAddress) 308 { 309 totalLength = MmGetMdlByteCount(Irp->MdlAddress); 310 311 } 312 313 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Transfer data length = %d\n", totalLength)); 314 if (totalLength>FBT_HCI_DATA_MAX_SIZE) 315 { 316 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Buffer exceeds maximum packet length (%d), failing IRP\n", FBT_HCI_DATA_MAX_SIZE)); 317 ntStatus = STATUS_INVALID_BUFFER_SIZE; 318 ExFreePool(rwContext); 319 goto FreeBT_DispatchWrite_Exit; 320 321 } 322 323 if (totalLength<FBT_HCI_DATA_MIN_SIZE) 324 { 325 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Zero length buffer, completing IRP\n")); 326 ntStatus = STATUS_BUFFER_TOO_SMALL; 327 ExFreePool(rwContext); 328 goto FreeBT_DispatchWrite_Exit; 329 330 } 331 332 virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress); 333 if (totalLength > deviceExtension->DataOutPipe.MaximumPacketSize) 334 { 335 stageLength = deviceExtension->DataOutPipe.MaximumPacketSize; 336 337 } 338 339 else 340 { 341 stageLength = totalLength; 342 343 } 344 345 mdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); 346 if (mdl == NULL) 347 { 348 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for mdl\n")); 349 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 350 ExFreePool(rwContext); 351 goto FreeBT_DispatchWrite_Exit; 352 353 } 354 355 // map the portion of user-buffer described by an mdl to another mdl 356 IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) virtualAddress, stageLength); 357 urb = (PURB) ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER)); 358 if (urb == NULL) 359 { 360 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for urb\n")); 361 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 362 ExFreePool(rwContext); 363 IoFreeMdl(mdl); 364 goto FreeBT_DispatchWrite_Exit; 365 366 } 367 368 UsbBuildInterruptOrBulkTransferRequest( 369 urb, 370 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 371 deviceExtension->DataOutPipe.PipeHandle, 372 NULL, 373 mdl, 374 stageLength, 375 USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT, 376 NULL); 377 378 // set FREEBT_RW_CONTEXT parameters. 379 rwContext->Urb = urb; 380 rwContext->Mdl = mdl; 381 rwContext->Length = totalLength - stageLength; 382 rwContext->Numxfer = 0; 383 rwContext->VirtualAddress = virtualAddress + stageLength; 384 385 // use the original read/write irp as an internal device control irp 386 nextStack = IoGetNextIrpStackLocation(Irp); 387 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 388 nextStack->Parameters.Others.Argument1 = (PVOID) urb; 389 nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 390 IoSetCompletionRoutine(Irp, 391 (PIO_COMPLETION_ROUTINE)FreeBT_WriteCompletion, 392 rwContext, 393 TRUE, 394 TRUE, 395 TRUE); 396 397 // We return STATUS_PENDING; call IoMarkIrpPending. 398 IoMarkIrpPending(Irp); 399 400 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); 401 if (!NT_SUCCESS(ntStatus)) 402 { 403 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: IoCallDriver fails with status %X\n", ntStatus)); 404 405 // if the device was yanked out, then the pipeInformation 406 // field is invalid. 407 // similarly if the request was cancelled, then we need not 408 // invoked reset pipe/device. 409 if((ntStatus != STATUS_CANCELLED) && (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) 410 { 411 ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->DataOutPipe.PipeHandle); 412 if(!NT_SUCCESS(ntStatus)) 413 { 414 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe failed\n")); 415 ntStatus = FreeBT_ResetDevice(DeviceObject); 416 417 } 418 419 } 420 421 else 422 { 423 FreeBT_DbgPrint(3, ("FBTUSB: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n")); 424 425 } 426 427 } 428 429 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite::")); 430 FreeBT_IoIncrement(deviceExtension); 431 432 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: URB sent to lower driver, IRP is pending\n")); 433 434 // we return STATUS_PENDING and not the status returned by the lower layer. 435 return STATUS_PENDING; 436 437 FreeBT_DispatchWrite_Exit: 438 Irp->IoStatus.Status = ntStatus; 439 Irp->IoStatus.Information = 0; 440 IoCompleteRequest(Irp, IO_NO_INCREMENT); 441 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Leaving\n")); 442 443 return ntStatus; 444 445 } 446 447 NTSTATUS NTAPI FreeBT_WriteCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) 448 { 449 ULONG stageLength; 450 NTSTATUS ntStatus; 451 PIO_STACK_LOCATION nextStack; 452 PFREEBT_RW_CONTEXT rwContext; 453 PDEVICE_EXTENSION deviceExtension; 454 455 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 456 rwContext = (PFREEBT_RW_CONTEXT) Context; 457 ntStatus = Irp->IoStatus.Status; 458 459 UNREFERENCED_PARAMETER(DeviceObject); 460 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Entered\n")); 461 462 if (NT_SUCCESS(ntStatus)) 463 { 464 if (rwContext) 465 { 466 rwContext->Numxfer += rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; 467 if (rwContext->Length) 468 { 469 // More data to transfer 470 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Initiating next transfer\n")); 471 if (rwContext->Length > deviceExtension->DataOutPipe.MaximumPacketSize) 472 { 473 stageLength = deviceExtension->DataOutPipe.MaximumPacketSize; 474 475 } 476 477 else 478 { 479 stageLength = rwContext->Length; 480 481 } 482 483 IoBuildPartialMdl(Irp->MdlAddress, rwContext->Mdl, (PVOID) rwContext->VirtualAddress, stageLength); 484 485 // reinitialize the urb 486 rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength; 487 rwContext->VirtualAddress += stageLength; 488 rwContext->Length -= stageLength; 489 490 nextStack = IoGetNextIrpStackLocation(Irp); 491 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 492 nextStack->Parameters.Others.Argument1 = rwContext->Urb; 493 nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 494 495 IoSetCompletionRoutine(Irp, 496 FreeBT_ReadCompletion, 497 rwContext, 498 TRUE, 499 TRUE, 500 TRUE); 501 502 IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); 503 504 return STATUS_MORE_PROCESSING_REQUIRED; 505 506 } 507 508 else 509 { 510 // No more data to transfer 511 FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion: Write completed, %d bytes written\n", Irp->IoStatus.Information)); 512 Irp->IoStatus.Information = rwContext->Numxfer; 513 514 } 515 516 } 517 518 } 519 520 else 521 { 522 FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion - failed with status = %X\n", ntStatus)); 523 524 } 525 526 if (rwContext) 527 { 528 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: ::")); 529 FreeBT_IoDecrement(deviceExtension); 530 531 ExFreePool(rwContext->Urb); 532 IoFreeMdl(rwContext->Mdl); 533 ExFreePool(rwContext); 534 535 } 536 537 538 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Leaving\n")); 539 540 return ntStatus; 541 542 } 543 544